mirror of
https://github.com/headroomlabs-ai/headroom.git
synced 2026-08-27 14:17:10 -04:00
67 commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
a3fe5cb65b
|
fix(onnx): enforce Rust API-24 runtime compatibility (#2979)
## Description Rust fastembed enables ORT C API 24, but the Python dependency allowed ONNX Runtime 1.23.2. Entering ort's initializer with that library deadlocks permanently instead of returning an error. Align dependency resolution where compatible wheels exist and preflight native detection where they do not. Closes #2960 ## Type of Change - [x] Bug fix (non-breaking change that fixes an issue) - [ ] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [ ] Documentation update - [ ] Performance improvement - [ ] Code refactoring (no functional changes) ## Changes Made - Require ONNX Runtime 1.24+ for Python 3.11+ in the proxy and voice extras. - Keep the available pre-1.24 runtime on Python 3.10 for Python ONNX consumers. - Refuse to auto-pin an incompatible runtime into the Rust extension. - Bypass native detection immediately when API 24 is unavailable, preserving Python fallback without a five-second watchdog delay or stuck native thread. - Add dependency, pinning, override, and router regression coverage. ## Testing - [x] Unit tests pass (`pytest`) - [x] Linting passes (`ruff check .`) - [ ] Type checking passes (`mypy headroom`) - [x] New tests added for new functionality - [x] Manual testing performed ### Test Output ```text $ uv run pytest -q tests/test_transforms/test_ort_dylib.py tests/test_onnx_dependency_contract.py tests/test_onnx_runtime.py tests/test_transforms/test_content_router.py 88 passed in 9.31s $ uv run ruff check headroom/_ort.py headroom/transforms/content_router.py tests/test_transforms/test_ort_dylib.py tests/test_onnx_dependency_contract.py All checks passed! ``` ## Real Behavior Proof - Environment: macOS arm64; Python 3.13.14 and uv-managed Python 3.10.20. - Exact command / steps: run the issue's direct `headroom._core.detect_content_type` call in a subprocess with a 12-second timeout on Python 3.13; run `_detect_content` on Python 3.10 after resolving the proxy extra. - Observed result: Python 3.13 resolves ORT 1.26.0 and native detection returns `json_array`; Python 3.10 resolves ORT 1.23.2, leaves `ORT_DYLIB_PATH` unset, reports compatibility false, and immediately returns the Python `json_array` fallback. - Not tested: Linux-specific shared-object execution locally; CI's existing Linux Rust job already preflights ORT 1.24+ and exercises native tests. ## Runtime Rollout Safety - Rollout-managed feature(s): Native Rust content detection. - Minimum rollout channel: Stable/default; this is a deadlock prevention guard. - Stable/default behavior changed: Python 3.11+ installs a compatible ORT; Python 3.10 skips incompatible native detection. - Kill switch / disable path: `HEADROOM_DETECT_BACKEND=python` remains available; an explicit `ORT_DYLIB_PATH` remains an operator override. - Unsafe override required: No. - Qualification impact: Native detection stays enabled only with API-24-compatible ORT. - Rollback path: Revert this PR, which restores the old watchdog-only degradation. ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [x] I have commented my code, particularly in hard-to-understand areas - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [x] I did **not** edit `CHANGELOG.md` — it is generated by release-please from my Conventional Commit PR title (a CI guard enforces this) ## Screenshots (if applicable) Not applicable. ## Additional Notes The large lockfile diff is dependency resolution: Python 3.10 keeps ORT 1.23.2 while 3.11+ resolves 1.26.0. The functional Python change is intentionally small and keeps explicit `ORT_DYLIB_PATH` overrides working. |
||
|
|
6077e5a149
|
fix(mcp): restore SDK v1 compatibility cap (#2978)
## Description PR #2963 widened the MCP dependency to 2.x while Headroom's live MCP server still uses the v1 low-level `Server.list_tools()` and `Server.call_tool()` decorators. Fresh installs therefore crash before serving tools. Restore the v1 cap until the explicit SDK 2.x port in #2658 lands, and pin that compatibility contract with a regression test. Closes #2977 ## Type of Change - [x] Bug fix (non-breaking change that fixes an issue) - [ ] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [ ] Documentation update - [ ] Performance improvement - [ ] Code refactoring (no functional changes) ## Changes Made - Restore `mcp>=1.28.1,<2.0.0` in the `proxy` and `mcp` extras. - Regenerate `uv.lock`, resolving MCP 1.28.1 and removing the incompatible 2.x transitive set. - Add a dependency-contract test covering both shipping extras. ## Testing - [x] Unit tests pass (`pytest`) - [x] Linting passes (`ruff check .`) - [ ] Type checking passes (`mypy headroom`) - [x] New tests added for new functionality - [x] Manual testing performed ### Test Output ```text $ uv run pytest -q tests/test_mcp_dependency_contract.py tests/test_ccr_mcp_server.py tests/test_cli/test_mcp.py 41 passed in 0.56s $ uv run ruff check tests/test_mcp_dependency_contract.py All checks passed! $ uv run ruff format --check tests/test_mcp_dependency_contract.py 1 file already formatted ``` ## Real Behavior Proof - Environment: macOS arm64, Python 3.13.14, uv-managed project environment. - Exact command / steps: resolve the `mcp` extra, inspect the installed SDK version and v1 decorators, then instantiate `HeadroomMCPServer(check_proxy=False)`. - Observed result: `1.28.1 True True`; server construction returns a v1 `Server` successfully. - Not tested: full stdio exchange against every external MCP client; existing MCP unit and CLI suites cover server setup and handlers. ## Runtime Rollout Safety - Rollout-managed feature(s): None; dependency resolution guard. - Minimum rollout channel: Stable/default. - Stable/default behavior changed: Fresh installs stop resolving the incompatible MCP SDK 2.x release. - Kill switch / disable path: Revert the dependency cap after #2658 lands. - Unsafe override required: No. - Qualification impact: MCP extras and proxy installs remain on the maintained MCP 1.x line. - Rollback path: Revert this PR; not recommended until the v2 server port is merged and tested. ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [x] I have commented my code, particularly in hard-to-understand areas - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [x] I did **not** edit `CHANGELOG.md` — it is generated by release-please from my Conventional Commit PR title (a CI guard enforces this) ## Screenshots (if applicable) Not applicable. ## Additional Notes The documentation change is the inline dependency rationale next to the cap. The long-term migration remains #2658; this PR deliberately does not mix that breaking SDK port into the release-blocker rollback. |
||
|
|
ecf130d3ac
|
deps: bump ruff from 0.15.17 to 0.15.22 in the pip-minor-patch group (#2501)
Bumps the pip-minor-patch group with 1 update: [ruff](https://github.com/astral-sh/ruff). Updates `ruff` from 0.15.17 to 0.15.22 <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/astral-sh/ruff/releases">ruff's releases</a>.</em></p> <blockquote> <h2>0.15.22</h2> <h2>Release Notes</h2> <p>Released on 2026-07-16.</p> <h3>Preview features</h3> <ul> <li>[<code>pycodestyle</code>] Add an autofix for <code>E402</code> (<a href="https://redirect.github.com/astral-sh/ruff/pull/22212">#22212</a>)</li> <li>[<code>refurb</code>] Allow subclassing builtins in stub files (<code>FURB189</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/26812">#26812</a>)</li> <li>[<code>ruff</code>] Add rule to replace <code>noqa</code> comments with <code>ruff:ignore</code> (<code>RUF105</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/26423">#26423</a>)</li> <li>[<code>ruff</code>] Add rule to use human-readable names in <code>ruff:ignore</code> comments (<code>RUF106</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/26682">#26682</a>)</li> <li>[<code>ruff</code>] Add rule to use human-readable names in configuration selectors (<code>RUF201</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/26772">#26772</a>)</li> </ul> <h3>Bug fixes</h3> <ul> <li>[<code>flake8-pyi</code>] Fix false positive in <code>__all__</code> (<code>PYI053</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/26872">#26872</a>)</li> </ul> <h3>Rule changes</h3> <ul> <li>[<code>pylint</code>] Ignore mutable type updates in <code>redefined-loop-name</code> (<code>PLW2901</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/25733">#25733</a>)</li> </ul> <h3>Performance</h3> <ul> <li>Avoid redundant lexer token bookkeeping (<a href="https://redirect.github.com/astral-sh/ruff/pull/26765">#26765</a>)</li> <li>Avoid redundant pending-indentation writes (<a href="https://redirect.github.com/astral-sh/ruff/pull/26774">#26774</a>)</li> <li>Avoid unnecessary identifier lookahead (<a href="https://redirect.github.com/astral-sh/ruff/pull/26525">#26525</a>)</li> <li>Reuse parser scratch buffers (<a href="https://redirect.github.com/astral-sh/ruff/pull/26798">#26798</a>)</li> </ul> <h3>Documentation</h3> <ul> <li>Document argfile support (<a href="https://redirect.github.com/astral-sh/ruff/pull/26803">#26803</a>)</li> <li>[<code>flake8-datetimez</code>] Clarify naming guidance for <code>datetime.today</code> (<code>DTZ002</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/26658">#26658</a>)</li> <li>[<code>pycodestyle</code>] Document <code>E731</code> fix safety (<a href="https://redirect.github.com/astral-sh/ruff/pull/26847">#26847</a>)</li> <li>[<code>ruff</code>] Clarify intentional async contexts for <code>unused-async</code> (<code>RUF029</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/26641">#26641</a>)</li> </ul> <h3>Contributors</h3> <ul> <li><a href="https://github.com/dwego"><code>@dwego</code></a></li> <li><a href="https://github.com/MichaReiser"><code>@MichaReiser</code></a></li> <li><a href="https://github.com/Joosboy"><code>@Joosboy</code></a></li> <li><a href="https://github.com/KaufmanDmitriy"><code>@KaufmanDmitriy</code></a></li> <li><a href="https://github.com/PeterJCLaw"><code>@PeterJCLaw</code></a></li> <li><a href="https://github.com/ntBre"><code>@ntBre</code></a></li> <li><a href="https://github.com/charliermarsh"><code>@charliermarsh</code></a></li> </ul> <h2>Install ruff 0.15.22</h2> <h3>Install prebuilt binaries via shell script</h3> <pre lang="sh"><code></tr></table> </code></pre> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Changelog</summary> <p><em>Sourced from <a href="https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md">ruff's changelog</a>.</em></p> <blockquote> <h2>0.15.22</h2> <p>Released on 2026-07-16.</p> <h3>Preview features</h3> <ul> <li>[<code>pycodestyle</code>] Add an autofix for <code>E402</code> (<a href="https://redirect.github.com/astral-sh/ruff/pull/22212">#22212</a>)</li> <li>[<code>refurb</code>] Allow subclassing builtins in stub files (<code>FURB189</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/26812">#26812</a>)</li> <li>[<code>ruff</code>] Add rule to replace <code>noqa</code> comments with <code>ruff:ignore</code> (<code>RUF105</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/26423">#26423</a>)</li> <li>[<code>ruff</code>] Add rule to use human-readable names in <code>ruff:ignore</code> comments (<code>RUF106</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/26682">#26682</a>)</li> <li>[<code>ruff</code>] Add rule to use human-readable names in configuration selectors (<code>RUF201</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/26772">#26772</a>)</li> </ul> <h3>Bug fixes</h3> <ul> <li>[<code>flake8-pyi</code>] Fix false positive in <code>__all__</code> (<code>PYI053</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/26872">#26872</a>)</li> </ul> <h3>Rule changes</h3> <ul> <li>[<code>pylint</code>] Ignore mutable type updates in <code>redefined-loop-name</code> (<code>PLW2901</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/25733">#25733</a>)</li> </ul> <h3>Performance</h3> <ul> <li>Avoid redundant lexer token bookkeeping (<a href="https://redirect.github.com/astral-sh/ruff/pull/26765">#26765</a>)</li> <li>Avoid redundant pending-indentation writes (<a href="https://redirect.github.com/astral-sh/ruff/pull/26774">#26774</a>)</li> <li>Avoid unnecessary identifier lookahead (<a href="https://redirect.github.com/astral-sh/ruff/pull/26525">#26525</a>)</li> <li>Reuse parser scratch buffers (<a href="https://redirect.github.com/astral-sh/ruff/pull/26798">#26798</a>)</li> </ul> <h3>Documentation</h3> <ul> <li>Document argfile support (<a href="https://redirect.github.com/astral-sh/ruff/pull/26803">#26803</a>)</li> <li>[<code>flake8-datetimez</code>] Clarify naming guidance for <code>datetime.today</code> (<code>DTZ002</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/26658">#26658</a>)</li> <li>[<code>pycodestyle</code>] Document <code>E731</code> fix safety (<a href="https://redirect.github.com/astral-sh/ruff/pull/26847">#26847</a>)</li> <li>[<code>ruff</code>] Clarify intentional async contexts for <code>unused-async</code> (<code>RUF029</code>) (<a href="https://redirect.github.com/astral-sh/ruff/pull/26641">#26641</a>)</li> </ul> <h3>Contributors</h3> <ul> <li><a href="https://github.com/dwego"><code>@dwego</code></a></li> <li><a href="https://github.com/MichaReiser"><code>@MichaReiser</code></a></li> <li><a href="https://github.com/Joosboy"><code>@Joosboy</code></a></li> <li><a href="https://github.com/KaufmanDmitriy"><code>@KaufmanDmitriy</code></a></li> <li><a href="https://github.com/PeterJCLaw"><code>@PeterJCLaw</code></a></li> <li><a href="https://github.com/ntBre"><code>@ntBre</code></a></li> <li><a href="https://github.com/charliermarsh"><code>@charliermarsh</code></a></li> </ul> <h2>0.15.21</h2> <p>Released on 2026-07-09.</p> <h3>Preview features</h3> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Commits</summary> <ul> <li><a href=" |
||
|
|
74403fe804
|
build(deps): bump gitpython from 3.1.50 to 3.1.54 in the uv group across 1 directory (#2575)
Bumps the uv group with 1 update in the / directory: [gitpython](https://github.com/gitpython-developers/GitPython). Updates `gitpython` from 3.1.50 to 3.1.54 <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/gitpython-developers/GitPython/releases">gitpython's releases</a>.</em></p> <blockquote> <h2>3.1.54 - Security</h2> <h2>What's Changed</h2> <ul> <li>Harden unsafe Git option validation by <a href="https://github.com/Byron"><code>@Byron</code></a> in <a href="https://redirect.github.com/gitpython-developers/GitPython/pull/2180">gitpython-developers/GitPython#2180</a></li> </ul> <p><strong>Full Changelog</strong>: <a href="https://github.com/gitpython-developers/GitPython/compare/3.1.53...3.1.54">https://github.com/gitpython-developers/GitPython/compare/3.1.53...3.1.54</a></p> <h2>3.1.53 - Security</h2> <h2>What's Changed</h2> <ul> <li>feat(submodule): add deinit method to Submodule (<a href="https://redirect.github.com/gitpython-developers/GitPython/issues/2014">#2014</a>) by <a href="https://github.com/mvanhorn"><code>@mvanhorn</code></a> in <a href="https://redirect.github.com/gitpython-developers/GitPython/pull/2129">gitpython-developers/GitPython#2129</a></li> <li>typing: introduce sensible basedpyright defaults by <a href="https://github.com/Byron"><code>@Byron</code></a> in <a href="https://redirect.github.com/gitpython-developers/GitPython/pull/2174">gitpython-developers/GitPython#2174</a></li> <li>fix: make <code>submodule.update()</code> after <code>submodule.deinit()</code> work by <a href="https://github.com/Byron"><code>@Byron</code></a> in <a href="https://redirect.github.com/gitpython-developers/GitPython/pull/2175">gitpython-developers/GitPython#2175</a></li> <li>Fix commit hooks respecting core.hooksPath by <a href="https://github.com/Siesta0217"><code>@Siesta0217</code></a> in <a href="https://redirect.github.com/gitpython-developers/GitPython/pull/2159">gitpython-developers/GitPython#2159</a></li> <li>fix: validate config section delimiters by <a href="https://github.com/Byron"><code>@Byron</code></a> in <a href="https://redirect.github.com/gitpython-developers/GitPython/pull/2176">gitpython-developers/GitPython#2176</a></li> </ul> <h2>New Contributors</h2> <ul> <li><a href="https://github.com/Siesta0217"><code>@Siesta0217</code></a> made their first contribution in <a href="https://redirect.github.com/gitpython-developers/GitPython/pull/2159">gitpython-developers/GitPython#2159</a></li> </ul> <p><strong>Full Changelog</strong>: <a href="https://github.com/gitpython-developers/GitPython/compare/3.1.52...3.1.53">https://github.com/gitpython-developers/GitPython/compare/3.1.52...3.1.53</a></p> <h2>3.1.52 Security</h2> <p><a href="https://github.com/gitpython-developers/GitPython/security/advisories/GHSA-rwj8-pgh3-r573">https://github.com/gitpython-developers/GitPython/security/advisories/GHSA-rwj8-pgh3-r573</a>: Environment-variable exfiltration via os.path.expandvars() on Repo.clone_from() URL</p> <h2>What's Changed</h2> <ul> <li>Skip cross-drive relative config test on Windows by <a href="https://github.com/Byron"><code>@Byron</code></a> in <a href="https://redirect.github.com/gitpython-developers/GitPython/pull/2171">gitpython-developers/GitPython#2171</a></li> <li>fix: preserve literal clone URLs by <a href="https://github.com/Byron"><code>@Byron</code></a> in <a href="https://redirect.github.com/gitpython-developers/GitPython/pull/2172">gitpython-developers/GitPython#2172</a></li> </ul> <p><strong>Full Changelog</strong>: <a href="https://github.com/gitpython-developers/GitPython/compare/3.1.51...3.1.52">https://github.com/gitpython-developers/GitPython/compare/3.1.51...3.1.52</a></p> <h2>3.1.51 - Security</h2> <h2>What's Changed</h2> <ul> <li>Add AI-disclosure and quality requirements to the contribution guidelines by <a href="https://github.com/Byron"><code>@Byron</code></a> in <a href="https://redirect.github.com/gitpython-developers/GitPython/pull/2143">gitpython-developers/GitPython#2143</a></li> <li>docs(cmd): clarify Git.execute() string vs list command argument by <a href="https://github.com/mvanhorn"><code>@mvanhorn</code></a> in <a href="https://redirect.github.com/gitpython-developers/GitPython/pull/2144">gitpython-developers/GitPython#2144</a></li> <li>Rewrite Git.execute() command parameter docstring per <a href="https://redirect.github.com/gitpython-developers/GitPython/issues/2146">#2146</a> by <a href="https://github.com/EliahKagan"><code>@EliahKagan</code></a> in <a href="https://redirect.github.com/gitpython-developers/GitPython/pull/2147">gitpython-developers/GitPython#2147</a></li> <li>Document init script behavior with multiple master remotes by <a href="https://github.com/EliahKagan"><code>@EliahKagan</code></a> in <a href="https://redirect.github.com/gitpython-developers/GitPython/pull/2148">gitpython-developers/GitPython#2148</a></li> <li>Bump git/ext/gitdb from <code>335c0f6</code> to <code>0a019a2</code> by <a href="https://github.com/dependabot"><code>@dependabot</code></a>[bot] in <a href="https://redirect.github.com/gitpython-developers/GitPython/pull/2149">gitpython-developers/GitPython#2149</a></li> <li>Support relative worktree paths (git 2.48+ worktree.useRelativePaths) by <a href="https://github.com/elovelan"><code>@elovelan</code></a> in <a href="https://redirect.github.com/gitpython-developers/GitPython/pull/2151">gitpython-developers/GitPython#2151</a></li> <li>Defer xfail condition evaluation with xfail_if_raises context manager by <a href="https://github.com/elovelan"><code>@elovelan</code></a> in <a href="https://redirect.github.com/gitpython-developers/GitPython/pull/2153">gitpython-developers/GitPython#2153</a></li> <li>Run more submodule tests on Cygwin (fix flaky xfails) by <a href="https://github.com/EliahKagan"><code>@EliahKagan</code></a> in <a href="https://redirect.github.com/gitpython-developers/GitPython/pull/2154">gitpython-developers/GitPython#2154</a></li> <li>Cut xtrace noise from POSIX-ownership diagnostic steps by <a href="https://github.com/EliahKagan"><code>@EliahKagan</code></a> in <a href="https://redirect.github.com/gitpython-developers/GitPython/pull/2156">gitpython-developers/GitPython#2156</a></li> <li>Support index diffs against the empty tree by <a href="https://github.com/puneetdixit200"><code>@puneetdixit200</code></a> in <a href="https://redirect.github.com/gitpython-developers/GitPython/pull/2155">gitpython-developers/GitPython#2155</a></li> <li>refactor: seperate out Progress type by <a href="https://github.com/LoeschMaximilian"><code>@LoeschMaximilian</code></a> in <a href="https://redirect.github.com/gitpython-developers/GitPython/pull/2157">gitpython-developers/GitPython#2157</a></li> <li>Bump <a href="https://github.com/astral-sh/ruff-pre-commit">https://github.com/astral-sh/ruff-pre-commit</a> from v0.15.12 to 0.15.15 in the pre-commit group by <a href="https://github.com/dependabot"><code>@dependabot</code></a>[bot] in <a href="https://redirect.github.com/gitpython-developers/GitPython/pull/2160">gitpython-developers/GitPython#2160</a></li> <li>Bump actions/checkout from 6 to 7 by <a href="https://github.com/dependabot"><code>@dependabot</code></a>[bot] in <a href="https://redirect.github.com/gitpython-developers/GitPython/pull/2164">gitpython-developers/GitPython#2164</a></li> <li>Bump git/ext/gitdb from <code>0a019a2</code> to <code>4950ea9</code> by <a href="https://github.com/dependabot"><code>@dependabot</code></a>[bot] in <a href="https://redirect.github.com/gitpython-developers/GitPython/pull/2165">gitpython-developers/GitPython#2165</a></li> <li>Bump <a href="https://github.com/astral-sh/ruff-pre-commit">https://github.com/astral-sh/ruff-pre-commit</a> from v0.15.15 to 0.15.20 in the pre-commit group by <a href="https://github.com/dependabot"><code>@dependabot</code></a>[bot] in <a href="https://redirect.github.com/gitpython-developers/GitPython/pull/2166">gitpython-developers/GitPython#2166</a></li> <li>Add Commit.is_shallow property; document stats() limitation at shallow boundary by <a href="https://github.com/harshitayadavv"><code>@harshitayadavv</code></a> in <a href="https://redirect.github.com/gitpython-developers/GitPython/pull/2167">gitpython-developers/GitPython#2167</a></li> <li>Allow relative config paths with includes by <a href="https://github.com/Byron"><code>@Byron</code></a> in <a href="https://redirect.github.com/gitpython-developers/GitPython/pull/2169">gitpython-developers/GitPython#2169</a></li> <li>Reject abbreviated forms of unsafe git options by <a href="https://github.com/Byron"><code>@Byron</code></a> in <a href="https://redirect.github.com/gitpython-developers/GitPython/pull/2168">gitpython-developers/GitPython#2168</a></li> </ul> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Commits</summary> <ul> <li><a href=" |
||
|
|
564e0a8d0f
|
fix(deps): bump h2 to 4.4.1 for CVE-2026-71554 (#2839)
## Description
`pip-audit` is currently red on every open PR. Not because of anything
in those branches — `uv.lock` pins `h2` at 4.3.0, and CVE-2026-71554 was
published against `h2 <=4.4.0`.
> h2 <=4.4.0 accepts request header blocks containing more than one Host
header, and forwards every Host header to the consuming application.
Where the consumer downgrades HTTP/2 to HTTP/1.1, the resulting request
carries two Host header lines, which is a request smuggling primitive
(CWE-444).
Fixed in 4.4.1.
Closes #
## Type of Change
- [x] Bug fix (non-breaking change that fixes an issue)
- [ ] New feature (non-breaking change that adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality to change)
- [ ] Documentation update
- [ ] Performance improvement
- [ ] Code refactoring (no functional changes)
## Changes Made
- `uv lock --upgrade-package h2`, which moves exactly two packages:
```
h2 4.3.0 -> 4.4.1
hpack 4.1.0 -> 4.2.0
```
`h2` arrives transitively via `httpx[http2]`, and the constraint in
`pyproject.toml` is already wide enough (`>=3,<5`), so only the lock
needed to move — no source or `pyproject.toml` change.
`requirements-prod.txt` is not checked in; the audit workflow exports it
from `uv.lock` at run time, so the lock bump is the entire fix.
## Testing
- [x] Unit tests pass (`pytest`)
- [ ] Linting passes (`ruff check .`)
- [ ] Type checking passes (`mypy headroom`)
- [ ] New tests added for new functionality
- [x] Manual testing performed
### Test Output
Reproduced the CI gate locally with the exact command from
`.github/workflows/security.yml`:
```text
$ uv export --frozen --no-dev --no-emit-project --no-hashes \
--extra all --format requirements-txt > requirements-prod.txt
$ grep -E '^(h2|hpack)==' requirements-prod.txt
h2==4.4.1
hpack==4.2.0
$ pip-audit -r requirements-prod.txt
No known vulnerabilities found
```
Before this change, the same command reported:
```text
Name | Version | ID | Fix Versions
h2 | 4.3.0 | CVE-2026-71554 | 4.4.1
Found 1 known vulnerability in 1 package
```
## Real Behavior Proof
- **Environment:** macOS, uv 0.9.x, Python 3.12.6.
- **Exact command / steps:** `uv lock --upgrade-package h2 --dry-run` to
confirm the blast radius, then the real lock, then the workflow's own
export + `pip-audit` invocation.
- **Observed result:** resolution touches only `h2` and `hpack`; 269
packages resolved with no other version movement. `pip-audit` goes from
1 known vulnerability to none.
- **Not tested:** HTTP/2 traffic against a live upstream. `h2` 4.4.1 is
a patch release on a library used transitively by `httpx`; Headroom does
not import `h2` directly (`grep -rn "import h2" headroom/` is empty), so
the exposure is whatever `httpx[http2]` does with it.
## Review Readiness
- [x] I have performed a self-review
- [x] This PR is ready for human review
## Checklist
- [x] My code follows the project's style guidelines
- [x] I have performed a self-review of my code
- [ ] I have commented my code, particularly in hard-to-understand areas
- [ ] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [x] New and existing unit tests pass locally with my changes
- [x] I did **not** edit `CHANGELOG.md`
## Additional Notes
N/A items above: no code changed, so ruff/mypy/new tests do not apply —
the verification that matters is the audit output, which is quoted in
full.
**Why this is standalone.** It surfaced while fixing CI on #2838, but it
is not caused by that branch and it blocks #2832 identically. Landing it
separately unblocks the gate for every open PR at once and keeps a
supply-chain bump out of an unrelated change.
**One unrelated warning the resolver prints**, noted so it is not
mistaken for a side effect of this PR:
```
warning: `pypdfium2==5.12.0` is yanked (reason: "Setup blunder breaking some
bindgen codepaths ... Wheels are valid and effectively identical to 5.12.1")
```
That predates this change and is not touched by it. Worth its own bump,
but not here.
|
||
|
|
64e203931b
|
fix(deps): enforce audited transitive dependency floors (#2791)
## Description Enforces patched minimum versions for the vulnerable transitive `aiohttp` and `cryptography` dependencies so future lockfile refreshes cannot reintroduce the pip-audit failures affecting open pull requests. Related to the shared Security / pip-audit failures across open PRs. ## Type of Change - [x] Bug fix (non-breaking change that fixes an issue) - [ ] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [ ] Documentation update - [ ] Performance improvement - [ ] Code refactoring (no functional changes) ## Changes Made - Enforces `aiohttp>=3.14.3` for PYSEC-2026-3545/3546/3547. - Enforces `cryptography>=50.0.0` for PYSEC-2026-3552/3553/3554. - Synchronizes the project version recorded in `uv.lock` with `pyproject.toml`. ## Testing - [x] Dependency audit passes (`pip-audit`) - [x] Lockfile validation passes (`uv lock --check`) - [ ] Unit tests pass (`pytest`) - [ ] Type checking passes (`mypy headroom`) - [x] Manual verification performed ### Test Output ```text $ uv lock --check Resolved 269 packages $ uv export --frozen --no-dev --no-emit-project --no-hashes --extra all --format requirements-txt | uvx --python 3.12 pip-audit -r /dev/stdin No known vulnerabilities found ``` ## Real Behavior Proof - Environment: Local macOS worktree using CPython 3.12.13 and the frozen production dependency export. - Exact command / steps: Validated the lockfile, exported every production dependency with the `all` extra, and audited that exact export with pip-audit. - Observed result: The lockfile resolved successfully and pip-audit reported no known vulnerabilities. - Not tested: Publishing or deployment; the refreshed GitHub CI suite covers builds, wheels, containers, security scans, and platform tests. ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Checklist - [x] My code follows the project style guidelines - [x] I have performed a self-review of my changes - [x] No explanatory code comments are required beyond the PYSEC constraint annotations - [x] Documentation changes are not required for transitive security floors - [x] My changes generate no new local warnings - [x] The dependency audit proves the security fix is effective - [ ] Full repository tests are delegated to GitHub CI - [x] I did not edit `CHANGELOG.md`; release-please owns it ## Screenshots (if applicable) N/A — dependency metadata only. ## Additional Notes The earlier Docker-native failure was a transient Docker Hub HTTP 502 while resolving `python:3.13-slim`; the build did not reach project code. A fresh CI suite is running on the current head. Co-authored-by: JD Davis <jd@jds-macbook-air.tail2a279.ts.net> |
||
|
|
0221e7f240
|
fix(deps): bump aiohttp and cryptography to clear the CVEs blocking 0.34.0 (#2753)
## Description
`Dependency audit (pip-audit)` is the **only** failing check on the
0.34.0 release PR (#2679), so this blocks the release regardless of what
else lands in it.
`aiohttp 3.14.1` carries three advisories, all reachable through the
`--extra all` production set that CI audits (transitive via `litellm` /
`instructor` / `kubernetes` / `fsspec`):
| CVE | Impact | Fixed in |
|---|---|---|
| CVE-2026-69243 | Request smuggling via an edge case in the WebSocket
upgrade procedure (server-side component) | 3.14.2 |
| CVE-2026-69244 | Out-of-bounds heap read in the C response parser
building an error message for a malformed response — an
attacker-controlled server can DoS the client | **3.14.3** |
| CVE-2026-59881 | Decompresses frames with RSV1 set even when
`permessage-deflate` was not negotiated | 3.14.2 |
3.14.3 is the floor that clears all three.
Closes #
## Type of Change
- [x] Bug fix (non-breaking change that fixes an issue)
## Changes Made
- Lock-only bump via `uv lock --upgrade-package aiohttp`. **No
`pyproject.toml` constraint added** — every parent already permits
3.14.3, so a floor would be redundant surface to maintain.
- The diff also syncs `headroom-ai` `0.32.0` → `0.33.0` in the lock. `uv
lock` rewrites that from `pyproject.toml` (`version = "0.33.0"`); the
lock's record of the project's own version was stale. Same drift #2663
targets — happy to drop this PR if #2663 lands first and you'd rather
keep them separate.
Diff is exactly two version changes (plus their wheel-hash blocks).
## Testing
- [x] Manual testing performed
- [x] Linting passes — no Python source touched
### Test Output
```text
$ uv lock --upgrade-package aiohttp
Resolved 269 packages in 2.91s
Updated aiohttp v3.14.1 -> v3.14.3
Updated headroom-ai v0.32.0 -> v0.33.0
$ git diff --stat uv.lock
uv.lock | 456 +++++++++++++++++-------------------
1 file changed, 234 insertions(+), 222 deletions(-)
$ git diff uv.lock | grep -E '^[+-]version = '
-version = "3.14.1"
+version = "3.14.3"
-version = "0.32.0"
+version = "0.33.0"
```
## Real Behavior Proof
- **Environment:** macOS 26.4 arm64, `uv` 0.x from Homebrew, isolated
git worktree off `upstream/main` @ `
|
||
|
|
2bb14d1ab2
|
fix(ci): align Ruff tooling versions (#2406)
## Description Ruff currently has three independent versions: `uv.lock` resolves `0.14.14`, pre-commit runs `0.9.4`, and CI installs `0.15.17`. Contributors can therefore pass one formatter path and fail another. Make the exact Ruff pin in `pyproject.toml` the source of truth, align the lockfile and pre-commit hook to it, and make CI read that pin through a deterministic consistency verifier instead of carrying another hardcoded version. Closes #2398 ## Type of Change - [x] Bug fix (non-breaking change that fixes an issue) - [ ] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that causes existing functionality to change) - [ ] Documentation update - [ ] Performance improvement - [ ] Code refactoring (no functional changes) ## Changes Made - Pin the existing `[dev]` Ruff dependency to `0.15.17`, the formatter baseline already used by CI. - Refresh only Ruff in `uv.lock` with `uv 0.11.29`. - Align `ruff-pre-commit` to `v0.15.17`. - Add `scripts/verify-ruff-version.py` and run it from pre-commit and CI. - Make CI install the verified version read from `pyproject.toml` rather than a separate literal. ## Testing - [ ] Unit tests pass (`pytest`) — not run; no runtime source or test behavior changed. - [x] Linting passes (`ruff check .`) - [x] Type checking passes (`mypy headroom`) - [x] New deterministic guard proves the configuration fix - [x] Manual testing performed ### Test Output ```text # Before: run the verifier with the patched pyproject pin but base-branch # uv.lock, pre-commit config, and workflow. Ruff version mismatch detected: uv.lock uses Ruff 0.14.14, expected 0.15.17 .pre-commit-config.yaml uses Ruff 0.9.4, expected 0.15.17 ci.yml does not run 'python scripts/verify-ruff-version.py --print-version' ci.yml does not install Ruff from 'steps.ruff-version.outputs.version' $ python3 scripts/verify-ruff-version.py Ruff versions aligned at 0.15.17 $ uvx uv@0.11.29 lock --check Resolved 269 packages $ uvx uv@0.11.29 tree --locked --package ruff ruff v0.15.17 $ uvx ruff@0.15.17 check . All checks passed! $ uvx ruff@0.15.17 format --check . 1322 files already formatted $ uvx mypy@1.20.2 headroom --ignore-missing-imports Success: no issues found in 505 source files $ uvx --with tomli mypy@1.20.2 scripts/verify-ruff-version.py --ignore-missing-imports Success: no issues found in 1 source file $ uvx pre-commit run ruff --all-files Passed $ uvx pre-commit run ruff-format --all-files Passed $ uvx pre-commit run verify-ruff-version --all-files Passed ``` ## Real Behavior Proof - Environment: macOS 26.5, Python 3.14.6 locally; Python 3.10 fallback also exercised; `uv 0.11.29`, Ruff `0.15.17`, mypy `1.20.2`. - Exact command / steps: reproduced the mismatch using the base branch's real `uv.lock`, `.pre-commit-config.yaml`, and `.github/workflows/ci.yml`; then ran the verifier, locked Ruff tree, full Ruff check/format, mypy, and actual pre-commit hooks after the patch. - Observed result: the base state fails with all four drift points listed; the patched state reports one aligned Ruff version (`0.15.17`) and every formatter path passes. - Not tested: runtime proxy behavior and the pytest suite, because the change is limited to development-tool configuration, lock metadata, pre-commit, and CI wiring. ## Dependency / Supply-Chain Justification - Ruff is an existing development-only formatter maintained by Astral; this PR adds no new package. - `0.15.17` is required to fix local/CI reproducibility and has already been the repository's CI formatter baseline since #1295. - Install surface is limited to the `[dev]` extra, lint CI job, and pre-commit environment. Production/runtime dependencies are unchanged. - The `uv.lock` refresh updates only Ruff; no unrelated dependency upgrades are included. ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [x] I have commented the non-obvious consistency checks - [x] Documentation changes are N/A; contributor commands are unchanged - [x] My changes generate no new warnings - [x] The guard fails on the real base-state mismatch and passes after the fix - [ ] New and existing unit tests pass locally — not run; no runtime code changed - [x] I did not edit `CHANGELOG.md`; release-please will use the conventional PR title ## Additional Notes No formatter-driven source changes are included. AI assistance was used to inspect configuration, implement the verifier, and run validation. |
||
|
|
494fb5a60e
|
fix(security): exclude compromised ast-grep-cli 0.44.1 (supply-chain trojan) (#2342)
## Description Fixes #2332. The `ast_grep_cli` **0.44.1** PyPI release was a compromised supply-chain build: it shipped an info-stealer `sg.exe` (212 KB, detected as `Trojan:Win64/Lazy!MTB`) alongside the legitimate `ast-grep` binary as camouflage. `headroom-ai` declares `ast-grep-cli>=0.30.0`, so a fresh PyPI install — `pip install "headroom-ai[all]"` or `uv tool install "headroom-ai[all]"` — can resolve the malicious 0.44.1 (the repo `uv.lock` protects only `uv sync`-from-source, not end users installing the published package). ## Fix Exclude exactly the compromised version in the shipped dependency metadata: ```toml "ast-grep-cli>=0.30.0,!=0.44.1", ``` `!=0.44.1` removes only the known-bad build, so every other release stays installable — older safe versions and any future patched release alike. The committed `uv.lock` already resolves to the safe **0.42.1**, which still satisfies the new constraint, so no re-resolution is needed; I updated the lock's `requires-dist` entry to match the new specifier to keep `uv lock --locked` consistent. ## Type of Change - [x] Bug fix (non-breaking change that fixes an issue) - [ ] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [ ] Documentation update - [ ] Performance improvement - [ ] Code refactoring (no functional changes) ## Changes Made - `pyproject.toml`: `ast-grep-cli` constraint is now `>=0.30.0,!=0.44.1`, with a comment recording why. - `uv.lock`: update the `ast-grep-cli` `requires-dist` specifier to match (resolved version unchanged at 0.42.1). ## Testing - [ ] Unit tests pass (`pytest`) - [x] Linting passes (`ruff check .`) - [x] Type checking passes (`mypy headroom`) - [ ] New tests added for new functionality - [ ] Manual testing performed ### Test Output ```text # Verified the specifier semantics with packaging: $ python -c "from packaging.specifiers import SpecifierSet; from packaging.version import Version; s=SpecifierSet('>=0.30.0,!=0.44.1'); print(Version('0.44.1') in s, [str(v) for v in ['0.42.1','0.44.0','0.44.2','0.45.0'] if Version(v) in s])" False ['0.42.1', '0.44.0', '0.44.2', '0.45.0'] # pyproject still parses and carries the new constraint: $ python -c "import tomllib; print([d for d in tomllib.load(open('pyproject.toml','rb'))['project']['dependencies'] if 'ast-grep' in d])" ['ast-grep-cli>=0.30.0,!=0.44.1'] ``` ## Real Behavior Proof - Environment: Windows 11, Python 3.12. - Exact command / steps: evaluated the new `SpecifierSet('>=0.30.0,!=0.44.1')` against the compromised version and a range of safe versions, and re-parsed `pyproject.toml`. - Observed result: `0.44.1` is excluded (`in` -> False); `0.42.1` (the current lock pin), `0.44.0`, `0.44.2`, `0.45.0`, and `1.0.0` all remain allowed; the pre-0.30 floor is still enforced. So a resolver can no longer select the trojaned build, and no legitimate release is blocked. - Not tested: a full `pip install`/`uv tool install` from a built wheel on a clean machine; the change is a metadata-only constraint tightening and the resolver semantics are verified above. ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [x] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [ ] New and existing unit tests pass locally with my changes - [ ] I have updated the CHANGELOG.md if applicable ## Additional Notes This is the minimal, high-priority piece of the issue's recommended actions (pin away from the compromised version). The issue also suggests an install-docs warning and a `pip-audit` / `uv audit` CI step; those are worth doing but are separate follow-ups (a CI workflow change I can't meaningfully validate here), so I left them out to keep this fix small and obviously correct. No CHANGELOG entry is added since this is a dependency-metadata security pin, but I'm happy to add one if the project prefers it here. Co-authored-by: JerrettDavis <mxjerrett@gmail.com> |
||
|
|
0fa337f64f
|
build(deps): refresh stale uv.lock (reconcile ~30 missing deps) (#2349)
## Description Refreshes the **stale `uv.lock`** and clears the mcp CVEs in one pass. main's lock had drifted far from `pyproject.toml` — a full `uv lock` (with the **CI-matching uv 0.11.29**, what `astral-sh/setup-uv@v5` installs) reconciles ~30 declared-but-unlocked dependencies and their transitives. This is the comprehensive counterpart to the minimal #2348. Closes # ## Type of Change - [x] Bug fix (security + dependency hygiene) ## Why it's this big `uv lock --check` **fails on `main`** (the committed lock predates several pyproject deps). CI hasn't caught it because the pipeline only ever runs `uv export --frozen` (consume-as-is), never a re-lock — so the drift accumulated silently. A correct lock is ~1100 lines of reconciliation. ## Changes Made - `pyproject.toml`: `mcp>=1.0.0` → `>=1.28.1` (core + `[mcp]` extra) — carried from the security fix. - `uv.lock`: full refresh via `uv lock` (uv 0.11.29). `mcp` → **1.28.1** (clears CVE-2026-52869/52870/59950); ~30 previously-missing deps added; transitives reconciled. ## Testing ```text uv 0.11.29 lock --check -> Resolved 269 packages (up to date, no error) uv export --frozen ... -> succeeds (CI pip-audit path) mcp in refreshed lock -> 1.28.1 ``` The transitive version changes are what `uv lock` produces for the current `pyproject.toml`; **CI's full test matrix is the validation gate** for behavior (that's the point of the shards). ## Relationship to #2348 **Superset.** #2348 is the minimal, surgical mcp bump (5-line diff) for immediate CVE closure with near-zero blast radius. This PR does the same mcp fix **plus** the full stale-lock reconciliation. Merge **one**: - Prefer low risk / fast → merge **#2348**, land this refresh separately afterwards. - Prefer fixing the lock drift now → merge **this**, close #2348. No `CHANGELOG.md` edit (release-please owns it). |
||
|
|
a90be94e32
|
fix(deps): bump mcp to 1.28.1 to clear 3 high-severity CVEs (#2348)
## Description Clears **all 3 open Dependabot alerts** (and the `pip-audit` CI failure) — every one is `mcp 1.26.0` in `uv.lock`: | Alert | CVE | Issue | Fix | |-------|-----|-------|-----| | #155 | CVE-2026-52870 | experimental task handlers leak cross-session tasks | 1.27.2 | | #156 | CVE-2026-52869 | HTTP transports serve session requests without auth check | 1.27.2 | | #157 | CVE-2026-59950 | deprecated WebSocket transport lacks Host/Origin validation | 1.28.1 | `mcp 1.28.1` satisfies all three. Closes # ## Type of Change - [x] Bug fix (security / dependency) ## Changes Made - `pyproject.toml`: raise the floor `mcp>=1.0.0` → `mcp>=1.28.1` (core dep **and** the `[mcp]` extra). - `uv.lock`: bump the `mcp` entry `1.26.0` → `1.28.1` (version + sdist/wheel URL, sha256, size from PyPI). **Surgical on purpose.** mcp 1.28.1's resolved dependency set is unchanged for this project's Python range (1.26 vs 1.28.1 differ only in `python_version>=3.14` conditionals and an httpx upper bound already satisfied), so no other locked package changes. Verified: `uv.lock` parses, `mcp = 1.28.1`, no `mcp-1.26.0` refs remain. ## Testing ```text python -c "import tomllib; ...; print(pkgs['mcp'])" -> 1.28.1 (uv.lock valid TOML) git diff --stat -> pyproject.toml | 4 ; uv.lock | 6 grep -c mcp-1.26.0 uv.lock -> 0 ``` mcp 1.28.1 ≥ every advisory's fixed-version, so all 3 alerts + pip-audit clear. ## Real Behavior Proof - Env: local; hashes fetched from `https://pypi.org/pypi/mcp/1.28.1/json`. - Steps: bumped the pyproject floor + the single mcp lock entry; validated TOML + version + absence of old refs. - Not tested: full `uv sync` (the lock is separately stale — see note). ## Note (deliberate scoping) A full `uv lock` refresh churns ~900 lines: the lock is **separately stale** (missing some declared deps) and local `uv` resolution diverges (major downgrades of protobuf/posthog/portalocker — likely an env artifact). That's a pre-existing lock-hygiene problem for its own PR — **not** bundled into this security fix. No `CHANGELOG.md` edit (release-please owns it). |
||
|
|
dec60de976
|
fix(codex): preserve wrapped sessions and recover state (#2160)
## Description Closes #2159. Codex wrappers currently launch against a disposable `CODEX_HOME`, so session state created during a wrapped run can disappear when that temporary directory is removed. This change launches Codex against its durable home, keeps proxy routing process-local, and adds recovery for retained temporary homes and pinned recovery sources. ## Type of Change - [x] Bug fix (non-breaking change that fixes an issue) - [ ] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [x] Documentation update - [ ] Performance improvement - [ ] Code refactoring (no functional changes) ## Changes Made - Launch Codex against its durable `CODEX_HOME` and apply routing through process-local config overrides after the actual proxy port is resolved. - Preserve custom provider identity and reject providers that cannot be redirected safely. - Detect dangling temporary Codex homes before interactive wraps and offer recovery. - Add `headroom recover codex` with automatic discovery, repeatable `--source`, preview, confirmation, retained backups, and rollback on failure. - Search Python's temp root, `$TMPDIR`, `/tmp`, `/private/tmp`, and macOS `/private/var/folders/*/*/T` for retained `headroom-codex-home-*` directories. - Reuse `source-pinned/` copies left by interrupted or failed recovery attempts after the original temporary home has disappeared. - Report deleted temporary homes still referenced by SQLite rollout paths without treating paths pasted into prompts or errors as filesystem evidence. - Audit the durable thread index, rollout files, and history when no source remains, including indexed chat counts and history-only orphan records. - Normalize legacy localhost `headroom` providers in both SQLite thread rows and rollout `session_meta`, including retries after an earlier broken recovery, while preserving user-defined remote providers named `headroom`. - Merge compatible config, JSONL, rollout, SQLite, credential, and regular-file state without propagating deletions or runtime artifacts. - Rewrite recovered thread rollout paths to the durable home and restore legacy Headroom thread providers to the active provider. - Validate SQLite schemas, SQLx migration checksums, integrity, and foreign keys, and quarantine malformed JSONL. - Preserve failed targets with an atomic rename before rollback, avoiding recursive-deletion races with live SQLite runtime files. - Document discovery, migration, retained backups, rollback behavior, and the limits of deleted-source recovery. ## Testing - [x] Unit tests pass (`pytest`) - [x] Linting passes (`ruff check`) - [x] Type checking passes (`mypy`) - [x] New tests added for new functionality - [x] Manual testing performed in isolated Docker containers ### Test Output ```text $ uv run pytest tests/test_cli/test_wrap_codex.py tests/test_cli/test_recover_codex.py -q 122 passed $ uv run ruff check headroom/cli/recover.py headroom/providers/codex/recovery.py tests/test_cli/test_recover_codex.py All checks passed! $ uv run ruff format --check headroom/cli/recover.py headroom/providers/codex/recovery.py tests/test_cli/test_recover_codex.py 3 files already formatted $ uv run mypy headroom/cli/recover.py headroom/providers/codex/recovery.py Success: no issues found in 2 source files ``` All validation ran in `ghcr.io/astral-sh/uv:python3.12-bookworm` against a writable disposable copy of a read-only source mount. Codex was not installed or launched, and no real user Codex state was read or modified. The tests cover multi-root discovery, deleted-reference reporting, retained pinned-source recovery, durable SQLite path relocation, SQLite and rollout provider normalization, idempotent repair after an earlier broken recovery, remote provider preservation, unrelated dangling target rows, backup retention, atomic rollback, malformed-state quarantine, SQLite validation, and Windows-safe handle closure. The repository shim E2E was not launched locally because this recovery work intentionally avoids launching Codex. Upstream CI exercises wrapper E2E in isolated environments. ## Real Behavior Proof - Environment: `ghcr.io/astral-sh/uv:python3.12-bookworm`, Python 3.12, a writable disposable checkout copied from a read-only source mount, at head ` |
||
|
|
fcf455a7eb
|
feat(wrap): add omp target (Oh My Pi) with models.yml override and unwrap (#1811)
## Description Adds `headroom wrap omp` / `headroom unwrap omp` — a one-command wrap for [Oh My Pi](https://www.npmjs.com/package/@oh-my-pi/pi-coding-agent) (`omp`), the pi-mono-lineage coding agent, as proposed in #1149. One honest correction to the issue: #1149 proposed reusing the `ANTHROPIC_BASE_URL` redirect from `wrap claude`. During implementation I probed that empirically and it turned out to be wrong — omp only reads `ANTHROPIC_BASE_URL` in its web-search helper; its **chat** endpoint comes from the model registry (`providers.anthropic.baseUrl` in `~/.omp/agent/models.yml`). With the env var pointed at a local probe server, omp's chat traffic still went straight to the real endpoint (0 probe hits); with a `models.yml` same-ID override, every request arrived at the probe (9/9 hits on `/v1/messages`). A same-ID override keeps omp's bundled Anthropic model catalog and stored credentials (both keyed by provider id `anthropic`), so only the endpoint moves. The wrap therefore injects a marker-fenced `providers.anthropic.baseUrl` override into `models.yml`, snapshotting the pre-wrap file **byte-for-byte** first, and `headroom unwrap omp` restores it exactly (or removes the file when the wrap created it) — the same durable-wrap + backup + unwrap contract `wrap codex` uses for `config.toml`. Closes #1149 ## Type of Change - [ ] Bug fix (non-breaking change that fixes an issue) - [x] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [ ] Documentation update - [ ] Performance improvement - [ ] Code refactoring (no functional changes) ## Changes Made - `headroom/providers/omp/` (new provider slice): `models_yml_path()` (honors `PI_CODING_AGENT_DIR`), `inject_models_override()` (yaml-merge preserving user providers; pristine byte-for-byte backup, never re-snapshotted while managed), `restore_models_override()` (`restored` / `removed` / `noop`; never touches an unmanaged file), `build_launch_env()` - `headroom/cli/wrap.py`: `wrap omp` (mirrors the aider/vibe `_launch_tool` shape; rtk instructions into the project's `AGENTS.md`, which omp reads natively) and `unwrap omp` (restore models.yml + scrub rtk block + stop proxy) - `headroom/telemetry/context.py`: `omp` added to `_KNOWN_WRAP_AGENTS` so the stack slug reports `wrap_omp` instead of `unknown` - `README.md` (agent matrix row + unwrap list), `llms.txt`, `CHANGELOG.md` - `tests/test_cli/test_wrap_omp.py`: 16 tests (injection fresh/merge/re-inject, restore statuses incl. unmanaged-file safety, env passthrough, CLI wiring, unwrap flows) ## Testing - [ ] Unit tests pass (`pytest`) — all new + `test_cli` tests pass; the full suite carries **3 pre-existing failures** that reproduce identically on unmodified `origin/main` (same set, same asserts — see Test Output and the rebase-validation comment) - [x] Linting passes (`ruff check .`) - [x] Type checking passes (`mypy headroom`) - [x] New tests added for new functionality - [x] Manual testing performed ### Test Output ```text $ uv run pytest -q # post-rebase, base |
||
|
|
cbfa267c5f
|
fix(deps): enforce transformers security floor (#2201)
## Description Raise the production `transformers` dependency floor so the security workflow cannot resolve the CVE-2026-5241 vulnerable range reported by `pip-audit`, and refresh the small current-main test fixtures needed for the PR matrix to run green. ## Type of Change - [x] Bug fix (non-breaking change that fixes an issue) - [ ] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [ ] Documentation update - [ ] Performance improvement - [ ] Code refactoring (no functional changes) ## Changes Made - Raised direct optional `transformers` declarations for `proxy`, `ml`, and `voice` extras to `>=5.5.0,<6.0`. - Refreshed `uv.lock` metadata so `uv export --extra all` resolves a patched `transformers` version for the production audit set. - Kept the current-main test fixture fixes for the ZCode setup printer and deferred compression fallback metrics. ## Testing - [x] Unit tests pass (`pytest`) - [x] Linting passes (`ruff check .`) - [ ] Type checking passes (`mypy headroom`) - [ ] New tests added for new functionality - [x] Manual testing performed ### Test Output ```text $ uv lock --check Resolved 238 packages in 1ms $ uv export --frozen --no-dev --no-emit-project --no-hashes --extra all --format requirements-txt | rg "^transformers==|^huggingface-hub==" huggingface-hub==1.16.1 transformers==5.13.1 $ uv export --frozen --no-dev --no-emit-project --no-hashes --extra all --format requirements-txt > requirements-prod.txt $ uvx pip-audit -r requirements-prod.txt No known vulnerabilities found $ uv run --with pytest --with pytest-asyncio --with fastapi --with httpx --with numpy pytest tests/test_cli/test_wrap_zcode.py::test_wrap_prints_proxy_urls tests/test_cold_start_fast_pass.py::test_fast_pass_failure_falls_back_to_full_deferral -q 2 passed $ uvx ruff==0.15.17 check headroom/cli/wrap.py headroom/proxy/handlers/anthropic.py --output-format concise All checks passed! $ git diff --check passed ``` ## Real Behavior Proof - Environment: Windows checkout plus the same frozen production dependency export shape used by the GitHub Actions security workflow. - Exact command / steps: raised the `transformers` floor, refreshed `uv.lock`, exported `--extra all` production requirements, ran `pip-audit`, then reproduced the focused ZCode and deferred-compression tests. - Observed result: the export resolves `transformers==5.13.1`; `pip-audit` reported no known vulnerabilities; the focused tests pass locally; CI is rerunning on the updated head. - Not tested: full GitHub Actions matrix locally; CI is running the complete suite on this PR. ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [ ] I have updated the CHANGELOG.md if applicable ## Screenshots (if applicable) N/A - dependency metadata and CI fixture fix. ## Additional Notes This PR is intentionally scoped to clearing the current red mainline security gate while keeping the small fixture updates needed by the branch test matrix. |
||
|
|
ea3d5a86b7
|
fix(deps): clear Dependabot lockfile alerts (#2175)
## Description Clears the current dependency/security-audit blockers that are making unrelated PRs red: - `transformers 5.3.0` / `CVE-2026-5241`, fixed by requiring `transformers>=5.5.0` in the locked optional dependency set. - `sqlitedict <=2.1.0` via the optional `benchmark` extra's `lm-eval[api]` dependency. There is no patched `sqlitedict` release, so this PR removes the published/locked `benchmark` extra instead of shipping a known-vulnerable transitive dependency. - `esbuild >=0.27.3,<0.28.1` in the OpenCode plugin lockfile, fixed by forcing `esbuild@0.28.1` through the OpenCode npm override and regenerated lockfile. The benchmark code still invokes `python -m lm_eval`; researchers who need that harness should install `lm-eval[api]` in their benchmark environment until its transitive vulnerability has a patched release. ## Type of Change - [x] Bug fix (non-breaking change that fixes an issue) - [ ] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [ ] Documentation update - [ ] Performance improvement - [ ] Code refactoring (no functional changes) ## Changes Made - `pyproject.toml`: remove the `benchmark` optional extra, document external `lm-eval[api]` installation guidance, and require `transformers>=5.5.0`. - `uv.lock`: regenerate without the `benchmark` extra, removing `lm-eval` and `sqlitedict` lock entries and locking the patched transformers floor. - `plugins/opencode/package.json`: add an `overrides` entry for `esbuild@0.28.1`. - `plugins/opencode/package-lock.json`: regenerate the OpenCode lockfile with `esbuild@0.28.1`. ## Testing - [x] Unit tests pass (`pytest`) - [x] Linting passes (`ruff check .`) - [ ] Type checking passes (`mypy headroom`) - [ ] New tests added for new functionality - [x] Manual testing performed ### Test Output ```text uv lock --check rg -n -F 'sqlitedict' uv.lock # no matches rg -n -F 'name = "lm-eval"' uv.lock # no matches rg -n -F "extra == 'benchmark'" uv.lock # no matches rg -n -F '0.27.7' plugins/opencode/package-lock.json plugins/opencode/package.json # no matches npm ls esbuild --package-lock-only npm audit --package-lock-only # found 0 vulnerabilities git diff --check ``` Previous GitHub checks were green. After merging current `main`, fresh GitHub checks are running again; local targeted validation still passes. ## Real Behavior Proof - Environment: Windows 11, Python 3.13.3, uv, npm in `plugins/opencode`, Dependabot/pip-audit alert metadata from the failing PR jobs. - Exact command / steps: inspected the regenerated Python and npm lockfiles with `rg`, checked the uv lock with `uv lock --check`, checked OpenCode's dependency tree with `npm ls esbuild --package-lock-only`, and ran `npm audit --package-lock-only`. - Observed result: `uv.lock` no longer contains `sqlitedict`, `lm-eval`, or a `benchmark` extra marker; `transformers` resolves at the patched `>=5.5.0` floor; OpenCode's lock resolves `esbuild@0.28.1`; `npm audit --package-lock-only` reports 0 vulnerabilities; GitHub `Dependency audit (pip-audit)` passes. - Not tested: running the external `lm-eval` harness after installing it separately. ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [ ] I have commented my code, particularly in hard-to-understand areas - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [x] I have updated the CHANGELOG.md if applicable ## Screenshots (if applicable) N/A - dependency and lockfile security fix. ## Additional Notes The `benchmark` extra can be restored once the upstream `lm-eval[api]` dependency chain stops pulling a vulnerable `sqlitedict` release. --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> |
||
|
|
4ea96a417c
|
feat(mcp): add streamable HTTP MCP transport (#1773)
## Description `headroom mcp serve` only exposed stdio, which blocked MCP clients that require a Streamable HTTP endpoint. This PR adds an explicit HTTP transport mode around the existing Headroom MCP server while keeping stdio as the default and keeping tool registration single-sourced. Closes #1346. ## Type of Change - [ ] Bug fix (non-breaking change that fixes an issue) - [x] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [x] Documentation update - [ ] Performance improvement - [ ] Code refactoring (no functional changes) ## Changes Made - Add `headroom mcp serve --transport http` with host, port, and path options. - Serve `headroom_compress`, `headroom_retrieve`, and `headroom_stats` through the same MCP server instance used by stdio. - Keep `headroom mcp serve` defaulting to stdio for current Claude Code and local MCP host configs. - Update MCP docs for stdio and HTTP setup without implying the proxy automatically owns `/mcp`. - Keep the scope clean, rebased, and covered by focused tests. ## Testing - [x] Unit tests pass (`uv run pytest tests/test_ccr_mcp_http.py tests/test_cli/test_mcp.py -q`) - [x] Linting passes (`uv run ruff check headroom/cli/mcp.py headroom/ccr/mcp_server.py headroom/ccr/mcp_http.py tests/test_ccr_mcp_http.py tests/test_cli/test_mcp.py`) - [x] Type checking passes (`uv run mypy headroom --ignore-missing-imports`) - [x] New tests added for new functionality when applicable - [x] Manual testing performed ### Test Output ```text uv run pytest tests/test_ccr_mcp_http.py tests/test_cli/test_mcp.py -q 20 passed in 0.53s uv run ruff check headroom/cli/mcp.py headroom/ccr/mcp_server.py headroom/ccr/mcp_http.py tests/test_ccr_mcp_http.py tests/test_cli/test_mcp.py All checks passed! uv run ruff format headroom/cli/mcp.py headroom/ccr/mcp_server.py headroom/ccr/mcp_http.py tests/test_ccr_mcp_http.py tests/test_cli/test_mcp.py --check 5 files already formatted uv run mypy headroom --ignore-missing-imports Success: no issues found in 407 source files ``` ## Real Behavior Proof - Environment: Local Python environment with Headroom dev dependencies and MCP extra installed. - Exact command / steps: Start `headroom mcp serve --transport http --host 127.0.0.1 --port <test-port> --path /mcp`, then perform an MCP SDK Streamable HTTP initialize/list-tools exchange. - Observed result: The HTTP transport initializes and lists the existing Headroom MCP tools; `headroom mcp serve` without `--transport` still selects stdio, and mixed-case `--transport HTTP` routes to the HTTP transport. - Not tested: live validation against external MCP hosts ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Additional Notes `CHANGELOG.md` is not edited because this repository generates changelog entries from conventional commits. Full-suite validation is left to CI. |
||
|
|
fce93bf39a
|
fix(ci/deps): clear audit and release smoke failures (#2190)
## Summary - add a uv constraint floor for `setuptools>=83.0.0` to address `PYSEC-2026-3447` - refresh `uv.lock` so the production audit export resolves with `setuptools 83.0.0` - harden the Release wheel smoke-import gate by retrying Ubuntu-container `apt-get` operations and using `--fix-missing` - keep the generated `requirements-prod.txt` uncommitted; it is produced by the security workflow ## Why This clears the new dependency audit alert that made PRs red: - `setuptools 80.10.2` - `PYSEC-2026-3447` - fixed in `83.0.0` While validating the queue, the same PR class also hit a Release smoke-import failure in the Ubuntu 22.04 ARM container due apt mirror skew: `E: Failed to fetch ... python3-httplib2_0.20.2-2ubuntu0.1_all.deb 404 Not Found` The smoke gate should still fail for broken wheels, but transient apt mirror skew should not make unrelated PRs red. ## Lockfile impact - `setuptools 80.10.2 -> 83.0.0` - `torch 2.12.1 -> 2.13.0`, required for pip resolver compatibility with `setuptools 83.0.0` in the exported audit set - `cuda-toolkit 13.0.2 -> 13.0.3.0`, pulled by the torch lock refresh - uv also refreshed the existing project metadata for the sandbox extra so `uv lock --check` passes ## Validation - `uv lock --check` - `uv export --frozen --no-dev --no-emit-project --no-hashes --extra all --format requirements-txt > requirements-prod.txt` - confirmed generated `requirements-prod.txt` contains `setuptools==83.0.0`, `torch==2.13.0`, `cuda-toolkit==13.0.3.0` - `uvx pip-audit -r requirements-prod.txt` -> No known vulnerabilities found - `python -m pytest tests/test_release_workflows.py -q` -> 32 passed - `uvx ruff@0.15.17 check tests/test_release_workflows.py` -> All checks passed - `git diff --check` |
||
|
|
0e9bda8891
|
chore(deps): bump agno from 2.4.5 to 2.6.6 in the uv group across 1 directory (#2166)
Bumps the uv group with 1 update in the / directory: [agno](https://github.com/agno-agi/agno). Updates `agno` from 2.4.5 to 2.6.6 <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/agno-agi/agno/releases">agno's releases</a>.</em></p> <blockquote> <h2>v2.6.6</h2> <h1>Changelog</h1> <h2>New Features:</h2> <ul> <li><strong>Slack Interface:</strong> Added support for HITL multi-row approvals with all pause types.</li> </ul> <h2>Improvements:</h2> <ul> <li><strong>WikiContextProvider:</strong> Added <code>NotionDatabaseBackend</code> to wiki context provider.</li> <li><strong>Tools:</strong> Updated to warn on duplicate tool names when registering on agent or team.</li> </ul> <h2>Bug Fixes:</h2> <ul> <li><strong>JWT:</strong> <ul> <li>fixed to bind user_id to JWT subject in traces and approvals routers</li> <li>fixed to bind WebSocket user_id to JWT subject for workflows</li> </ul> </li> <li><strong>RunOutput: f</strong>ixed <code>aget_last_run_output</code> returns None when <code>agent.id</code> is auto-generated during <code>arun()</code>.</li> <li><strong><code>/continue</code> Endpoint:</strong> Fixed to forward dependencies and metadata to /continue endpoints via <code>get_request_kwargs</code>.</li> <li><strong>LearningMachine:</strong> Fixed to inject LearningMachine context into Team system prompt.</li> </ul> <h2>What's Changed</h2> <ul> <li>fix: bind user_id to JWT subject in traces and approvals routers by <a href="https://github.com/ysolanky"><code>@ysolanky</code></a> in <a href="https://redirect.github.com/agno-agi/agno/pull/7816">agno-agi/agno#7816</a></li> <li>fix: bind WebSocket user_id to JWT subject to prevent IDOR by <a href="https://github.com/ysolanky"><code>@ysolanky</code></a> in <a href="https://redirect.github.com/agno-agi/agno/pull/7817">agno-agi/agno#7817</a></li> <li>feat: add api client header to gemini connectors by <a href="https://github.com/markmcd"><code>@markmcd</code></a> in <a href="https://redirect.github.com/agno-agi/agno/pull/7828">agno-agi/agno#7828</a></li> <li>fix: warn on duplicate tool names when registering on agent or team by <a href="https://github.com/ysolanky"><code>@ysolanky</code></a> in <a href="https://redirect.github.com/agno-agi/agno/pull/7829">agno-agi/agno#7829</a></li> <li>fix: add Anthropic context window patterns to CONTEXT_WINDOW_PATTERNS by <a href="https://github.com/marcospin"><code>@marcospin</code></a> in <a href="https://redirect.github.com/agno-agi/agno/pull/7836">agno-agi/agno#7836</a></li> <li>fix: <code>aget_last_run_output</code> returns None when agent.id is auto-generated during <code>arun()</code> by <a href="https://github.com/kausmeows"><code>@kausmeows</code></a> in <a href="https://redirect.github.com/agno-agi/agno/pull/7840">agno-agi/agno#7840</a></li> <li>fix: forward dependencies and metadata to /continue endpoints via get_request_kwargs by <a href="https://github.com/ysolanky"><code>@ysolanky</code></a> in <a href="https://redirect.github.com/agno-agi/agno/pull/7849">agno-agi/agno#7849</a></li> <li>fix: inject LearningMachine context into Team system prompt by <a href="https://github.com/Mustafa-Esoofally"><code>@Mustafa-Esoofally</code></a> in <a href="https://redirect.github.com/agno-agi/agno/pull/7818">agno-agi/agno#7818</a></li> <li>chore: update S3 bucket URL from phidata-public to agno-public by <a href="https://github.com/irfaan101"><code>@irfaan101</code></a> in <a href="https://redirect.github.com/agno-agi/agno/pull/7844">agno-agi/agno#7844</a></li> <li>fix: pin <code>tree-sitter-language-pack</code><1.8.0 to unblock chonkie code chunker by <a href="https://github.com/sannya-singal"><code>@sannya-singal</code></a> in <a href="https://redirect.github.com/agno-agi/agno/pull/7869">agno-agi/agno#7869</a></li> <li>feat: Slack HITL multi-row approvals with all pause types by <a href="https://github.com/Mustafa-Esoofally"><code>@Mustafa-Esoofally</code></a> in <a href="https://redirect.github.com/agno-agi/agno/pull/7574">agno-agi/agno#7574</a></li> <li>fix: disable agno[mistral] (mistralai quarantined on PyPI) by <a href="https://github.com/harshsinha03"><code>@harshsinha03</code></a> in <a href="https://redirect.github.com/agno-agi/agno/pull/7877">agno-agi/agno#7877</a></li> <li>[FIX] newsletter link in README by <a href="https://github.com/kyleaton"><code>@kyleaton</code></a> in <a href="https://redirect.github.com/agno-agi/agno/pull/7900">agno-agi/agno#7900</a></li> <li>cookbook: rewrite 01_demo as minimal AgentOS demo by <a href="https://github.com/ashpreetbedi"><code>@ashpreetbedi</code></a> in <a href="https://redirect.github.com/agno-agi/agno/pull/7906">agno-agi/agno#7906</a></li> <li>feat: add NotionDatabaseBackend to wiki context provider by <a href="https://github.com/ashpreetbedi"><code>@ashpreetbedi</code></a> in <a href="https://redirect.github.com/agno-agi/agno/pull/7914">agno-agi/agno#7914</a></li> <li>chore: Release v2.6.6 by <a href="https://github.com/kausmeows"><code>@kausmeows</code></a> in <a href="https://redirect.github.com/agno-agi/agno/pull/7915">agno-agi/agno#7915</a></li> </ul> <h2>New Contributors</h2> <ul> <li><a href="https://github.com/markmcd"><code>@markmcd</code></a> made their first contribution in <a href="https://redirect.github.com/agno-agi/agno/pull/7828">agno-agi/agno#7828</a></li> <li><a href="https://github.com/marcospin"><code>@marcospin</code></a> made their first contribution in <a href="https://redirect.github.com/agno-agi/agno/pull/7836">agno-agi/agno#7836</a></li> <li><a href="https://github.com/irfaan101"><code>@irfaan101</code></a> made their first contribution in <a href="https://redirect.github.com/agno-agi/agno/pull/7844">agno-agi/agno#7844</a></li> </ul> <p><strong>Full Changelog</strong>: <a href="https://github.com/agno-agi/agno/compare/v2.6.5...v2.6.6">https://github.com/agno-agi/agno/compare/v2.6.5...v2.6.6</a></p> <h2>v2.6.5</h2> <h1>Changelog</h1> <h2>New Features:</h2> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Commits</summary> <ul> <li><a href=" |
||
|
|
e9000863fc
|
fix(kompress): fail-open wall-clock guard on single-cache-miss compression (#2114)
## Description The single-cache-miss branch in `ContentRouter` ran compression inline on the request path without its own wall-clock guard, so a cooperative stall waited for the full call even when `HEADROOM_COMPRESSION_DEADLINE_MS` was meant to fail open. This change adds a branch-level watchdog that returns `PASSTHROUGH` after the deadline, scoped only to the one-pending-task path and not the native GIL-hold root cause. Closes #2046 ## Type of Change - [x] Bug fix (non-breaking change that fixes an issue) - [ ] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [ ] Documentation update - [ ] Performance improvement - [ ] Code refactoring (no functional changes) ## Changes Made - Added `_compression_deadline_seconds()` and a watchdog around the single-cache-miss inline compression branch in `ContentRouter`. - Returned the original content with `PASSTHROUGH` and logged a fail-open warning after the configured deadline, while preserving under-deadline and deadline-disabled behavior. - Added focused regressions for timeout, under-deadline output, and disabled-deadline behavior, then kept the wider deadline suite green. - Raised the locked production floors for `click` and `pillow` to clear the current `pip-audit` findings that now fail external PR merge snapshots. ## Testing - [x] Unit tests pass (`uv run pytest tests/test_content_router_single_item_deadline.py tests/test_transforms/test_kompress_deadline.py -q`) - [x] Linting passes (`uv run ruff check headroom/transforms/content_router.py tests/test_content_router_single_item_deadline.py tests/test_transforms/test_kompress_deadline.py`) - [ ] Type checking passes (`uv run mypy headroom`) - [x] New tests added for new functionality - [x] Manual testing performed ### Test Output ```text uv run pytest tests/test_content_router_single_item_deadline.py tests/test_transforms/test_kompress_deadline.py -q ============================= test session starts ============================= platform win32 -- Python 3.12.13, pytest-9.0.3, pluggy-1.6.0 rootdir: D:\Repos\headroom-pr-2046-compression-freeze configfile: pyproject.toml plugins: anyio-4.12.1, langsmith-0.9.3, asyncio-1.3.0, cov-7.0.0 asyncio: mode=Mode.AUTO, debug=False, asyncio_default_fixture_loop_scope=None, asyncio_default_test_loop_scope=function collected 5 items tests\test_content_router_single_item_deadline.py ... [ 60%] tests\test_transforms\test_kompress_deadline.py .. [100%] ============================== 5 passed in 0.42s ============================== uv run ruff check headroom/transforms/content_router.py tests/test_content_router_single_item_deadline.py tests/test_transforms/test_kompress_deadline.py All checks passed! uv run ruff format headroom/transforms/content_router.py tests/test_content_router_single_item_deadline.py tests/test_transforms/test_kompress_deadline.py --check 3 files already formatted ``` ## Real Behavior Proof - Environment: Windows, Python 3.12.13, router-level harness with a cooperative slow-compression stub - Exact command / steps: `uv run pytest tests/test_content_router_single_item_deadline.py tests/test_transforms/test_kompress_deadline.py -q`, which forces one frozen prefix and one cache miss, then sleeps past a 10 ms deadline - Observed result: the guarded branch returns the original content through `PASSTHROUGH` at the deadline, while under-deadline and deadline-disabled behavior stay unchanged - Not tested: native GIL-holding freeze ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [x] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [ ] I have updated the CHANGELOG.md if applicable ## Screenshots (if applicable) Not applicable. ## Additional Notes - Security CI currently flags `click 8.3.1` and `pillow 12.2.0`, so this PR carries the narrow floor bump to `click>=8.3.3` and `pillow>=12.3.0` as a supply-chain unblock for the same final merge snapshot. - `CHANGELOG.md` remains untouched because Headroom generates release notes from conventional commits. - This PR is a Python-side mitigation for the single-cache-miss branch only; the native GIL-hold root cause remains a separate owner. --------- Co-authored-by: JerrettDavis <mxjerrett@gmail.com> |
||
|
|
09be107d06
|
fix(deps): raise transformers security floor
Raise the production transformers floor to a version fixed for CVE-2026-5241 and refresh uv.lock so pip-audit passes. |
||
|
|
8870b6971f
|
fix(deps): bump pillow to 12.3.0 and click to 8.4.2 (#2097)
## Description
Pip-audit found 6 vulnerabilities in 2 packages in the lockfile:
| Package | From | To | Vulns Fixed |
|---------|------|----|-------------|
| click | 8.3.1 | 8.4.2 | PYSEC-2026-2132 |
| pillow | 12.2.0 | 12.3.0 | PYSEC-2026-2253~2257 |
Closes #N/A (no issue filed — security workflow failure)
## Type of Change
- [x] Bug fix (non-breaking)
- [ ] New feature (non-breaking)
- [ ] Breaking change
- [ ] Documentation update
## Changes Made
- `uv.lock`: Upgraded click from 8.3.1 to 8.4.2, pillow from 12.2.0 to
12.3.0
## Testing
- [x] `uv lock --upgrade-package` resolved cleanly
- [x] `ruff check headroom/` passes
- [x] CLI import verified (click 8.4.2 loads correctly)
```
$ uv run python -c "import click; print(click.__version__)"
click: 8.4.2
$ uv tree --depth=1 | grep -E "click|pillow"
click v8.4.2
pillow v12.3.0 (extra: all)
pillow v12.3.0 (extra: image)
```
## Real Behavior Proof
- Environment: headroom main (upstream/main
|
||
|
|
4f3d5ab341
|
fix(install): add orjson to [proxy] extra for LiteLLM provider backends (#2074)
## Description Add `orjson` to the `[proxy]` extra so `uv tool install "headroom-ai[all]"` installs a runtime dependency required by LiteLLM provider backends (e.g. OpenRouter). ## Type of Change - [x] Bug fix (non-breaking change which fixes an issue) - [ ] New feature - [ ] Breaking change - [ ] Documentation update ## Changes Made - Add `orjson>=3.9.14; platform_python_implementation != 'PyPy'` to `[proxy]`. - Regression test in `tests/test_optional_dependencies.py`. - Minimal `uv.lock` update (proxy/all optional-deps + metadata only). ## Motivation Fixes #2056. `headroom-ai[all]` installs `litellm` (core dep) but not `orjson`. LiteLLM provider backends import `orjson` at runtime; LiteLLM only declares it under `litellm[proxy]`, not base deps. Headroom does not depend on `litellm[proxy]` (would pull the full LiteLLM proxy server stack). ## Testing - `uv run --extra dev python -m pytest tests/test_optional_dependencies.py -q` — 2 passed - `uvx --from ruff==0.15.17 ruff check tests/test_optional_dependencies.py` - `uvx --from ruff==0.15.17 ruff format --check tests/test_optional_dependencies.py` ## Real Behavior Proof - **Setup:** Ubuntu, Python 3.12.3 - **Verified:** dependency graph test confirms `orjson` is selected for `[proxy]` and `[all]` extras after this patch. - **Not tested locally:** full `uv tool install` end-to-end (local sdist build requires Rust/C++ toolchain unavailable in this environment). Reporter workaround `uv tool install ... --with orjson` confirms the missing transitive dep diagnosis. ## Review Readiness - [x] I have performed a self-review of my code - [x] This PR is ready for human review ## Notes - Reporter used Python 3.14.4; `litellm` is intentionally skipped on 3.14 (GH #956). This PR fixes the missing `orjson` install path for supported Python versions using `[all]`. Co-authored-by: syf2211 <syf2211@users.noreply.github.com> Co-authored-by: JerrettDavis <mxjerrett@gmail.com> Co-authored-by: Tejas Chopra <chopratejas@gmail.com> |
||
|
|
fd0d29c92d
|
fix(packaging): guard torch extras on intel macos (#2011)
## Description Closes #1931 Guard the `ml` and `voice` `torch` optional dependencies on macOS x86_64 so `headroom-ai[all]` remains resolvable on Intel Macs where PyTorch does not publish compatible wheels for this version floor. The lockfile metadata is updated with the same markers. ## Type of Change - [x] Bug fix (non-breaking change which fixes an issue) - [ ] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] Documentation update - [ ] Refactoring - [ ] Performance improvement - [ ] Test update - [ ] Other ## Changes Made - Added macOS x86_64 environment markers to `torch` in the `ml` and `voice` extras. - Updated `uv.lock` optional dependency metadata to match the guarded extras. - Added a packaging regression test that checks `[all]` keeps `ml` and `voice` while guarding `torch` on macOS x86_64. ## Testing - [x] Unit tests pass (`pytest`) - [x] Linting passes (`ruff check`) - [x] Formatting verified (`ruff format --check`) - [ ] Manual testing performed ### Test Output ```text $ python3 -m pytest tests/test_optional_dependencies.py -q collected 1 item tests/test_optional_dependencies.py . [100%] ============================== 1 passed in 0.26s =============================== $ .venv/bin/ruff check tests/test_optional_dependencies.py All checks passed! $ .venv/bin/ruff format --check tests/test_optional_dependencies.py pyproject.toml 1 file already formatted ``` ## Test verification (RED -> GREEN) RED, with the `torch` markers temporarily removed from `pyproject.toml`: ```text tests/test_optional_dependencies.py F [100%] FAILED tests/test_optional_dependencies.py::test_all_extra_does_not_require_torch_on_macos_x86_64 E assert False ``` GREEN, with this patch applied: ```text tests/test_optional_dependencies.py . [100%] ============================== 1 passed in 0.26s =============================== ``` ## Real Behavior Proof - Environment: Linux, Python 3.12.3, pytest 9.1.1, ruff 0.14.14. - Exact command / steps: Removed the environment markers from `torch`, ran the new packaging test, restored the markers, and reran the test plus targeted ruff checks. - Observed result: The test fails without the macOS x86_64 guard and passes once the `ml` and `voice` `torch` requirements are guarded. - Not tested: Full `uv run pytest`, full-project `uv run ruff check .`, full-project `uv run ruff format --check .`, and `uv run mypy headroom` were not run locally for this targeted packaging change. ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Checklist - [x] My code follows the style guidelines of this project - [x] I have performed a self-review of my code - [x] I have added tests that prove my fix is effective - [x] New and existing targeted tests pass locally with my changes - [x] Any dependent changes have been merged and published in downstream modules ## Screenshots (if applicable) N/A ## Additional Notes No new dependency is added; this only narrows when the existing `torch` optional dependency is selected. |
||
|
|
28ca61fc9d
|
fix: patch nltk vulnerability (CVE-2026-54293) (#1929)
## Description
Updates the locked `nltk` package from 3.9.4 to 3.10.0 to address
CVE-2026-54293, reported by OrbisAI Security as an information
disclosure/path traversal issue in `nltk.data.load()`.
Closes #
## Type of Change
- [x] Bug fix (non-breaking change that fixes an issue)
- [ ] New feature (non-breaking change that adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality to change)
- [ ] Documentation update
- [ ] Performance improvement
- [ ] Code refactoring (no functional changes)
## Changes Made
- Updated the `nltk` lockfile entry from 3.9.4 to 3.10.0.
- Added the new locked `defusedxml` dependency required by `nltk`
3.10.0.
- Added an explicit `nltk>=3.10.0` uv constraint so future lock
refreshes cannot regress below the fixed version.
- Updated the benchmark-extra comment now that the nltk CVE has an
upstream fixed release.
## Testing
<!-- Check what you actually ran, then paste the real command output
below. -->
- [ ] Unit tests pass (`pytest`)
- [ ] Linting passes (`ruff check .`)
- [ ] Type checking passes (`mypy headroom`)
- [ ] New tests added for new functionality
- [x] Manual testing performed
### Test Output
```text
uv lock --locked
Resolved 257 packages in 1ms
uv run --extra benchmark python -c "import importlib.metadata as md; print('lm-eval', md.version('lm-eval')); print('rouge-score', md.version('rouge-score')); print('nltk', md.version('nltk'))"
lm-eval 0.4.10
rouge-score 0.1.2
nltk 3.10.0
```
## Real Behavior Proof
- Environment: GitHub pull request diff for
headroomlabs-ai/headroom#1929.
- Exact command / steps: Reviewed the PR diff and ran the focused uv
lock/import checks listed above.
- Observed result: The lockfile now points at nltk 3.10.0 artifacts,
includes the new defusedxml dependency, and records the nltk>=3.10.0
resolver constraint.
- Not tested: Full local test suite was not run for this lockfile-only
security update.
## Review Readiness
- [x] I have performed a self-review
- [x] This PR is ready for human review
## Checklist
- [x] My code follows the project's style guidelines
- [x] I have performed a self-review of my code
- [x] I have commented my code, particularly in hard-to-understand areas
- [x] I have made corresponding changes to the documentation
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective or that my
feature works
- [ ] New and existing unit tests pass locally with my changes
- [ ] I have updated the CHANGELOG.md if applicable
## Screenshots (if applicable)
N/A.
## Additional Notes
Original automated security context from OrbisAI Security:
- CVE: CVE-2026-54293
- Severity: HIGH
- Scanner: trivy
- Rule: `CVE-2026-54293`
- File: `uv.lock`
- Assessment: Likely exploitable
- Description: nltk information disclosure via path traversal in
`nltk.data.load()`.
---------
Co-authored-by: JerrettDavis <mxjerrett@gmail.com>
|
||
|
|
662b7bc00e
|
fix(release): sync all package versions to v0.31.0 (#1882)
## Description Current `main` has advanced the core package versions to `0.31.0`, but the plugin marketplace manifests and hook plugin manifests were still left at `0.30.0`. This PR now keeps the original version-sync intent while updating the remaining metadata to the current release line. It also preserves the previously-added `lxml-html-clean>=0.4.5` security floor in `pyproject.toml` / `uv.lock` so the security audit remains unblocked. Closes #1872 ## Type of Change - [x] Bug fix (non-breaking change that fixes an issue) - [ ] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [ ] Documentation update - [ ] Performance improvement - [ ] Code refactoring (no functional changes) ## Changes Made - Synced `pyproject.toml`, SDK/package manifests, plugin manifests, marketplaces, `.release-please-manifest.json`, and editable package lock metadata to `0.31.0`. - Updated the OpenClaw plugin dependency on `headroom-ai` to `^0.31.0`. - Merged current `main` and resolved the version metadata conflicts in favor of current `0.31.0` alignment. ## Testing - [x] Unit tests pass (`pytest tests/test_plugin_manifests.py scripts/tests/test_version_sync.py -q`) - [ ] Linting passes (`ruff check .`) - [ ] Type checking passes (`mypy headroom`) - [ ] New tests added for new functionality - [x] Manual testing performed (`python scripts/verify-versions.py`) ### Test Output ```text python scripts/verify-versions.py All versions aligned at 0.31.0 pytest tests/test_plugin_manifests.py scripts/tests/test_version_sync.py -q 10 passed in 0.42s ``` ## Real Behavior Proof - Environment: Windows, Python 3.13.13, PR head after merging current `main`. - Exact command / steps: Ran `python scripts/verify-versions.py` and `pytest tests/test_plugin_manifests.py scripts/tests/test_version_sync.py -q`. - Observed result: Version verification exits successfully with `All versions aligned at 0.31.0`; focused manifest/version-sync tests pass. - Not tested: Full wheel/build matrix; this is metadata-only version alignment and CI will cover the broader matrix. ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [x] My changes generate no new warnings - [x] New and existing focused tests pass locally with my changes - [ ] I have made corresponding changes to the documentation - [ ] I have updated the CHANGELOG.md if applicable --------- Co-authored-by: JerrettDavis <mxjerrett@gmail.com> |
||
|
|
0ba5065d40
|
Tejas/tool search deferral (#1885)
## Description <!-- Briefly explain the change and why it is needed. --> Closes # ## Type of Change - [ ] Bug fix (non-breaking change that fixes an issue) - [ ] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [ ] Documentation update - [ ] Performance improvement - [ ] Code refactoring (no functional changes) ## Changes Made - ## Testing <!-- Check what you actually ran, then paste the real command output below. --> - [ ] Unit tests pass (`pytest`) - [ ] Linting passes (`ruff check .`) - [ ] Type checking passes (`mypy headroom`) - [ ] New tests added for new functionality - [ ] Manual testing performed ### Test Output ```text # Paste relevant command output or artifact links here ``` ## Real Behavior Proof - Environment: - Exact command / steps: - Observed result: - Not tested: ## Review Readiness - [ ] I have performed a self-review - [ ] This PR is ready for human review ## Checklist - [ ] My code follows the project's style guidelines - [ ] I have performed a self-review of my code - [ ] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [ ] My changes generate no new warnings - [ ] I have added tests that prove my fix is effective or that my feature works - [ ] New and existing unit tests pass locally with my changes - [ ] I have updated the CHANGELOG.md if applicable ## Screenshots (if applicable) Add screenshots to help explain your changes. ## Additional Notes <!-- Mention any N/A checklist items, tradeoffs, follow-ups, or maintainer context. --> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
12060a6219
|
chore(deps): bump transformers from 5.0.0 to 5.3.0 in the uv group across 1 directory (#1662)
Bumps the uv group with 1 update in the / directory: [transformers](https://github.com/huggingface/transformers). Updates `transformers` from 5.0.0 to 5.3.0 <details> <summary>Release notes</summary> <p><em>Sourced from <a href="https://github.com/huggingface/transformers/releases">transformers's releases</a>.</em></p> <blockquote> <h2>v5.1.0: EXAONE-MoE, PP-DocLayoutV3, Youtu-LLM, GLM-OCR</h2> <h2>New Model additions</h2> <h3>EXAONE-MoE</h3> <!-- raw HTML omitted --> <p>K-EXAONE is a large-scale multilingual language model developed by LG AI Research. Built using a Mixture-of-Experts architecture, K-EXAONE features 236 billion total parameters, with 23 billion active during inference. Performance evaluations across various benchmarks demonstrate that K-EXAONE excels in reasoning, agentic capabilities, general knowledge, multilingual understanding, and long-context processing.</p> <ul> <li>Add EXAONE-MoE implementations (<a href="https://redirect.github.com/huggingface/transformers/issues/43080">#43080</a>) by <a href="https://github.com/nuxlear"><code>@nuxlear</code></a></li> </ul> <h3>PP-DocLayoutV3</h3> <!-- raw HTML omitted --> <p><strong>PP-DocLayoutV3</strong> is a unified and high-efficiency model designed for comprehensive layout analysis. It addresses the challenges of complex physical distortions—such as skewing, curving, and adverse lighting—by integrating instance segmentation and reading order prediction into a single, end-to-end framework.</p> <ul> <li>[Model] Add PP-DocLayoutV3 Model Support (<a href="https://redirect.github.com/huggingface/transformers/issues/43098">#43098</a>) by <a href="https://github.com/zhang-prog"><code>@zhang-prog</code></a></li> </ul> <h3>Youtu-LLM</h3> <!-- raw HTML omitted --> <p>Youtu-LLM is a new, small, yet powerful LLM, contains only 1.96B parameters, supports 128k long context, and has native agentic talents. On general evaluations, Youtu-LLM significantly outperforms SOTA LLMs of similar size in terms of Commonsense, STEM, Coding and Long Context capabilities; in agent-related testing, Youtu-LLM surpasses larger-sized leaders and is truly capable of completing multiple end2end agent tasks.</p> <ul> <li>Add Youtu-LLM model (<a href="https://redirect.github.com/huggingface/transformers/issues/43166">#43166</a>) by <a href="https://github.com/LuJunru"><code>@LuJunru</code></a></li> </ul> <h3>GlmOcr</h3> <!-- raw HTML omitted --> <p>GLM-OCR is a multimodal OCR model for complex document understanding, built on the GLM-V encoder–decoder architecture. It introduces Multi-Token Prediction (MTP) loss and stable full-task reinforcement learning to improve training efficiency, recognition accuracy, and generalization. The model integrates the CogViT visual encoder pre-trained on large-scale image–text data, a lightweight cross-modal connector with efficient token downsampling, and a GLM-0.5B language decoder. Combined with a two-stage pipeline of layout analysis and parallel recognition based on PP-DocLayout-V3, GLM-OCR delivers robust and high-quality OCR performance across diverse document layouts.</p> <ul> <li>[GLM-OCR] GLM-OCR Support (<a href="https://redirect.github.com/huggingface/transformers/issues/43391">#43391</a>)by <a href="https://github.com/zRzRzRzRzRzRzR"><code>@zRzRzRzRzRzRzR</code></a></li> </ul> <h2>Breaking changes</h2> <ul> <li> <p>🚨 T5Gemma2 model structure (<a href="https://redirect.github.com/huggingface/transformers/issues/43633">#43633</a>) - Makes sure that the attn implementation is set to all sub-configs. The config.encoder.text_config was not getting its attn set because we aren't passing it to PreTrainedModel.<strong>init</strong>. We can't change the model structure without breaking so I manually re-added a call to self.adjust_attn_implemetation in modeling code</p> </li> <li> <p>🚨 Generation cache preparation (<a href="https://redirect.github.com/huggingface/transformers/issues/43679">#43679</a>) - Refactors cache initialization in generation to ensure sliding window configurations are now properly respected. Previously, some models (like Afmoe) created caches without passing the model config, causing sliding window limits to be ignored. This is breaking because models with sliding window attention will now enforce their window size limits during generation, which may change generation behavior or require adjusting sequence lengths in existing code.</p> </li> <li> <p>🚨 Delete duplicate code in backbone utils (<a href="https://redirect.github.com/huggingface/transformers/issues/43323">#43323</a>) - This PR cleans up backbone utilities. Specifically, we have currently 5 different config attr to decide which backbone to load, most of which can be merged into one and seem redundant After this PR, we'll have only one config.backbone_config as a single source of truth. The models will load the backbone from_config and load pretrained weights only if the checkpoint has any weights saved. The overall idea is same as in other composite models. A few config arguments are removed as a result.</p> </li> <li> <p>🚨 Refactor DETR to updated standards (<a href="https://redirect.github.com/huggingface/transformers/issues/41549">#41549</a>) - standardizes the DETR model to be closer to other vision models in the library.</p> </li> <li> <p>🚨Fix floating-point precision in JanusImageProcessor resize (<a href="https://redirect.github.com/huggingface/transformers/issues/43187">#43187</a>) - replaces an <code>int()</code> with <code>round()</code>, expect light numerical differences</p> </li> <li> <p>🚨 Remove deprecated AnnotionFormat (<a href="https://redirect.github.com/huggingface/transformers/issues/42983">#42983</a>) - removes a missnamed class in favour of <code>AnnotationFormat</code>.</p> </li> </ul> <!-- raw HTML omitted --> </blockquote> <p>... (truncated)</p> </details> <details> <summary>Commits</summary> <ul> <li><a href=" |
||
|
|
4db3bc91d9
|
fix(bedrock): add boto3 1.41 + CRT for aws login credentials (#1486)
## Description `pip install headroom-ai[bedrock]` cannot serve users who authenticate with `aws login` (IAM Identity Provider / console-login, DPoP). Resolving those credentials requires the AWS Common Runtime (CRT); without `awscrt`, botocore raises `MissingDependencyException`. The AWS docs state the requirement as: **"Boto3 version 1.41.0 or later with AWS Common Runtime (CRT)"** — i.e. both a modern boto3 floor and CRT (installed via the `[crt]` extra). ## Type of Change - [x] Bug fix (non-breaking) ## Changes Made - `pyproject.toml` `bedrock` extra: bump `boto3>=1.28.0` → `boto3>=1.41.0`, add `botocore[crt]>=1.41.0` (installs `awscrt`). - `uv.lock`: regenerated — adds `awscrt`, resolves `boto3` to 1.42.x. No code changes — the bedrock backend already passes `aws_profile_name` through to the LiteLLM calls (via #1456); this just makes the installed dependencies actually able to resolve `aws login` credentials. ## Impact - **`aws login` (IAM Identity Provider / DPoP):** now works — awscrt present. - **`aws sso login` (classic Identity Center):** unaffected (already worked). - **static keys (`~/.aws/credentials`):** unaffected. - Bumping the boto3 floor only affects the optional `[bedrock]` extra; bedrock users benefit from a current boto3 regardless. ## Testing Dependency-only change. `uv lock` resolves cleanly (257 packages, awscrt 0.29.2, boto3 1.42.38). No runtime code path altered, so existing bedrock tests are unaffected. ## Checklist - [x] Self-review performed - [x] No new warnings - [x] Linting passes ## Additional Notes Focused on the dependency gap only. ARN routing / named-profile wiring / docs are handled in #1456; pricing in #1485. |
||
|
|
5771a8020e
|
fix(deps): remediate dependency CVEs and publish SBOM (#1509)
## Description
Supply-chain hardening: takes the **shipped** dependency surface from
**26 known CVEs to 0**. `pip install headroom-ai[all]` now resolves with
no known vulnerabilities (verified with Anchore syft + grype). Also
publishes a checked-in SBOM package (`sbom/`) so any user — especially
pilots running their own security review — can verify what's inside and
that we track it.
This addresses the Dependabot alerts on `main` (9 high / 4 moderate / 7
low at time of writing).
Closes #
## Type of Change
- [x] Bug fix (non-breaking change that fixes an issue)
- [ ] New feature (non-breaking change that adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality to change)
- [x] Documentation update
- [ ] Performance improvement
- [ ] Code refactoring (no functional changes)
## Changes Made
**Rust**
- `pyo3` 0.24 → 0.29 (GHSA-36hh-v3qg-5jq4 High, GHSA-chgr-c6px-7xpp
Med). Migrated `Python::allow_threads` → `Python::detach` (10 sites) and
added `from_py_object` to the `Clone`-deriving `#[pyclass]` types (both
required by the 0.25+ API).
- `pyo3-log` 0.12 → 0.13; `lru` 0.12 → 0.18 (GHSA-rhfx-m35p-ff5j).
**Python**
- `torch` → 2.12.1, `mem0ai` → 2.x.
- Floor-pinned transitive CVE deps via `[tool.uv]
constraint-dependencies`: `pygments>=2.20.0`,
`pydantic-settings>=2.14.2`, `gitpython>=3.1.50`, `langsmith>=0.9.0`.
- **Removed `benchmark` from the `[all]` aggregate** so the default
install is CVE-free. `lm-eval` is invoked as an external subprocess
(`python -m lm_eval`) and never imported, so it is not a true runtime
dep — it remains available via the opt-in `[benchmark]` extra. See
[Accepted Risks](#additional-notes).
**npm (build/test tooling — never shipped in the
wheel/container/published SDK)**
- `esbuild` override `>=0.28.1` in `sdk/typescript` + `plugins/openclaw`
(GHSA-g7r4-m6w7-qqqr).
- `docs/`: `@anthropic-ai/sdk` → `^0.106.0` (GHSA-p7fg-763f-g4gf),
`postcss` override to force Next.js's bundled copy ≥8.5.10
(GHSA-qx2v-qp2m-jg93); regenerated a stale `bun.lock` that carried a
**Critical** vitest/vite.
**CI**
- Pinned `pypa/gh-action-pypi-publish` `@release/v1` → `@v1.13.0`
(GHSA-vxmw-7h4f-hqxh) in `release.yml` + `publish.yml`.
**SBOM**
- New `sbom/` directory: CycloneDX 1.7 + SPDX 2.3 SBOMs, grype scan
evidence, 330-package license inventory, and a regeneration guide.
## Testing
- [ ] Unit tests pass (`pytest`) — N/A, no Python source changed
(deps/config only)
- [x] Linting passes — `cargo fmt --check` + `cargo clippy` clean on the
changed crate; 0 `.py` files changed so `ruff`/`mypy` scope is
unaffected
- [x] Type checking passes — `cargo check --workspace` (0 errors)
- [ ] New tests added — N/A (dependency bumps; covered by existing
suites)
- [x] Manual testing performed — see Real Behavior Proof
### Test Output
```text
# headroom-ai[all] product surface — the number that matters
$ grype sbom:sbom/headroom-sbom-all-extra.cdx.json
No vulnerabilities found
# full repo scan (universal lock incl. opt-in [benchmark] + dev)
$ grype sbom:sbom/headroom-sbom.cdx.json
NAME INSTALLED TYPE VULNERABILITY SEVERITY
sqlitedict 2.1.0 python GHSA-g4r7-86gm-pgqc High # [benchmark]-only, unpatchable, accepted
nltk 3.9.4 python GHSA-p4gq-832x-fm9v High # [benchmark]-only, unpatchable, accepted
# pyo3 0.29 migration — extension builds + imports + runs
$ cargo check --workspace
Finished `dev` profile [unoptimized + debuginfo] target(s)
$ maturin develop && python -c "from headroom._core import DiffCompressor, SmartCrusher; ..."
extension OK — detach + from_py_object paths exercised
# lru 0.18 — eviction path
$ cargo test -p headroom-proxy --lib drift
14 passed, 213 filtered out
# per-ecosystem npm audits
$ (cd sdk/typescript && npm audit) -> found 0 vulnerabilities
$ (cd plugins/openclaw && npm audit) -> found 0 vulnerabilities
$ (cd docs && npm audit && bun audit) -> found 0 vulnerabilities / No vulnerabilities found
```
## Real Behavior Proof
- Environment: macOS (darwin 25.4.0, arm64), Python 3.12 `.venv`, Rust
1.95 toolchain, syft 1.46.0, grype 0.115.0, bun 1.3.14, maturin 1.13.3.
- Exact command / steps: (1) `uv export --extra all --no-dev
--no-emit-project | syft → grype` for the product surface; (2) `cargo
check --workspace` + `maturin develop` + extension import/compress smoke
test; (3) `cargo test -p headroom-proxy --lib drift`; (4) `cargo fmt
--check` + `cargo clippy -p headroom-py`; (5) `npm audit` in
sdk/openclaw/docs + `bun audit` in docs.
- Observed result: `headroom-ai[all]` resolution scans clean — "No
vulnerabilities found" (179 pkgs); full/prod SBOM shows only the 2
documented accepted CVEs; pyo3 0.29 extension imports and runs (detach +
from_py_object paths exercised); drift tests 14/14 pass; cargo fmt +
clippy clean; all npm/bun audits report 0.
- Not tested: full `pytest` suite (no Python source changed);
release-profile wheel build (used dev-profile `maturin develop` for the
import proof — the extension is semantically identical).
## Review Readiness
- [x] I have performed a self-review
- [x] This PR is ready for human review
## Checklist
- [x] My code follows the project's style guidelines
- [x] I have performed a self-review of my code
- [x] I have commented my code, particularly in hard-to-understand areas
- [x] I have made corresponding changes to the documentation
(`sbom/README.md`)
- [x] My changes generate no new warnings
- [ ] I have added tests that prove my fix is effective — N/A
(dependency bumps; existing suites + scans cover it)
- [x] New and existing unit tests pass locally with my changes
- [ ] I have updated the CHANGELOG.md — N/A (Release Please
auto-generates from the conventional commit)
## Additional Notes
**Accepted risks (the 2 residual CVEs).** Both originate solely from the
EleutherAI `lm-evaluation-harness` under the **opt-in `[benchmark]`
extra**, which Headroom invokes as a subprocess (never imports):
- `sqlitedict` CVE-2024-35515 (High) — pickle deserialization; package
abandoned (last release 2021), **no upstream fix exists**.
- `nltk` CVE-2026-54293 (High) — path traversal in `nltk.data.load()`;
affects ≤3.9.4 (current latest), **no patched release**.
Neither is in `[all]`, the published wheel, or the container. They are
documented in `sbom/README.md` and will be picked up automatically once
upstream ships fixes.
**Release/CHANGELOG:** N/A items above are because this is a
dependency/security PR with no Python source changes; CHANGELOG is
Release-Please-managed via the conventional commit message.
|
||
|
|
35939c3536
|
fix(dashboard): include RTK stats in the historical tab (#1324)
## Description Restart the proxy, open the dashboard, go to the Historical tab and the RTK stats are gone. The Session tab shows them fine, Historical just doesn't have them. The reason is where the two tabs get their numbers. The Session tab calls `_get_context_tool_stats()` live, which reads RTK's own stats file. The Historical tab calls `history_response()`, which only contains the persisted proxy-compression data. RTK savings are never written into that savings JSON, they live in the RTK tool's separate stats file, so after a restart Historical has nothing to show for them. The fix makes `/stats-history` do the same thing `/stats` already does: pull the live RTK stats with `_get_context_tool_stats()` and attach them to the history response under a `cli_filtering` key (with `tool`, `label`, `lifetime` and `session`). The Historical tab then renders an RTK card from `historyStats.cli_filtering.lifetime.tokens_saved`. A few notes: 1. The card is hidden when `cli_filtering` is null, so setups without RTK look exactly as they do today. No empty card, no errors. 2. Reading the RTK stats is best-effort: if `_get_context_tool_stats()` raises (missing file, parse error, IO), `cli_filtering` falls back to null and the Historical tab stays available rather than returning a 500. 3. Nothing about how RTK stats are stored changed, we just read them on the history endpoint too, so there's no migration. Closes #1177 ## Type of Change - [x] Bug fix (non-breaking change that fixes an issue) - [ ] New feature (non-breaking change that adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to change) - [ ] Documentation update - [ ] Performance improvement - [ ] Code refactoring (no functional changes) ## Changes Made - `headroom/proxy/server.py`: the `/stats-history` handler now attaches live RTK stats under `cli_filtering`, the same source `/stats` uses, wrapped in best-effort error handling; the endpoint docstring documents the curated shape. - `headroom/dashboard/templates/dashboard.html`: add an RTK card to the Historical tab, hidden when there's no RTK data. - `tests/test_proxy_savings_history.py`: `test_stats_history_includes_cli_filtering`. ## Testing - [x] Unit tests pass (`pytest`) - [x] Linting passes (`ruff check`) - [x] Type checking passes (`mypy headroom`) - [x] New tests added for new functionality - [ ] Manual testing performed ### Test Output ```text $ uv run --extra dev python -m pytest tests/test_proxy_savings_history.py -q passed ruff: All checks passed! mypy: Success: no issues found ``` ## Real Behavior Proof - Environment: macOS, Python 3.13, this branch. - Exact command / steps: `uv run --extra dev python -m pytest tests/test_proxy_savings_history.py::test_stats_history_includes_cli_filtering`. The test hits `/stats-history` and asserts the payload carries `cli_filtering` with the RTK numbers the Historical tab reads. - Observed result: the `/stats-history` response now carries `cli_filtering` (`tool`/`label`/`lifetime`/`session`), the field the Historical tab was missing after a restart. `ruff` and `mypy` are clean on the changed files. - Not tested: I did not click through the rendered dashboard after a real restart, and this repo's test suite needs the native `_core` extension built (CI builds it), so the assertion runs in CI. The data the tab consumes is covered by the test, and the card is gated on that data being present. ## Review Readiness - [x] I have performed a self-review - [x] This PR is ready for human review ## Checklist - [x] My code follows the project's style guidelines - [x] I have performed a self-review of my code - [x] I have commented my code, particularly in hard-to-understand areas - [ ] I have made corresponding changes to the documentation - [x] My changes generate no new warnings - [x] I have added tests that prove my fix is effective or that my feature works - [x] New and existing unit tests pass locally with my changes - [x] I have updated the CHANGELOG.md if applicable ## Additional Notes |
||
|
|
b4571cc346
|
feat: headroom wrap opencode / unwrap opencode CLI (#1105)
## Summary This PR implements transparent `headroom wrap opencode` support without asking users to edit OpenCode provider URLs, choose an extra CLI flag, or maintain a static provider list. The wrapper now lives at the runtime transport boundary: OpenCode keeps its user/provider config, while Headroom intercepts outbound provider traffic in-process and routes it through the local Headroom proxy. ## What changed ### Transparent OpenCode wrapping - `headroom wrap opencode` injects the `headroom-opencode` plugin through `OPENCODE_CONFIG_CONTENT`. - Existing OpenCode provider URLs are preserved. We do not rewrite user config URLs to point at Headroom. - Existing `OPENAI_BASE_URL` and `ANTHROPIC_BASE_URL` env vars are preserved. - Local OpenCode traffic, localhost traffic, and Headroom proxy traffic bypass the shim to avoid loops. ### Runtime transport interception - Added an OpenCode plugin transport shim that wraps: - `globalThis.fetch` - `http.request` / `http.get` - `https.request` / `https.get` - External provider calls are routed to the local Headroom proxy. - The original upstream origin is passed through `x-headroom-base-url`, so the proxy can forward to the real provider without changing OpenCode config. - External `http2.connect` is blocked loudly instead of allowing direct provider traffic to leak outside Headroom. ### Live provider additions Provider coverage is no longer based on a static config scan. Because routing happens at outbound request time, providers added mid-session are routed through Headroom automatically as long as they use the covered Node transport paths. ### Subagent and child-process coverage - The parent OpenCode plugin sets a packaged Node preload shim through `NODE_OPTIONS=--import=.../hook-shim/handler.js`. - The transport shim patches `child_process.spawn`, `exec`, `execFile`, and `fork` so child Node processes receive the Headroom preload even when OpenCode passes a custom `env`. - The child-process shim fails closed if it loads without `HEADROOM_OPENCODE_TRANSPORT_PROXY_URL`. - This closes the subagent leak path where a child Node process could otherwise start without Headroom transport interception. ## Why this goes beyond PR #1089 PR #1089 improves OpenCode provider registration, but it still focuses on provider config shape. This PR moves the enforcement boundary to runtime transport interception. This PR goes further because: - No provider URL rewriting is required. - New providers added mid-session are covered automatically. - Subagents and child Node processes inherit the Headroom transport shim. - Direct external HTTP/2 paths fail loudly instead of leaking. - The wrap remains transparent to the user's OpenCode provider config. - The wrapper is fail-closed for unsupported child-process preload state. ## Additional robustness fixes While validating the change in Docker, the full Python suite exposed unrelated Linux/container robustness issues. These are fixed in this PR so the suite is green: - Binary cache handling now treats cache paths under a non-writable existing parent as unavailable, including when tests run as root in Docker. - `release_version.py` honors `MANUAL_VER` before git calls so direct script execution works outside a `.git` checkout. - Test logger isolation now resets relevant Headroom child loggers so proxy logging setup cannot poison later `caplog` tests. - The scanner missing-path test now uses a guaranteed missing `tmp_path` child instead of relying on `/nonexistent/path`. ## Validation All implementation validation was run inside Docker. - Full Python suite from a fresh Docker copy: `6605 passed, 523 skipped`. - Ruff on changed Python/OpenCode paths: passed. - OpenCode plugin typecheck: passed. - OpenCode plugin tests: `9 passed`. - OpenCode plugin build: passed. - Hook shim preload smoke test: passed. ## Notes This PR intentionally does not add a CLI option. `headroom wrap opencode` means full wrap. Either Headroom wraps OpenCode transparently, or the path fails loudly instead of silently leaking provider traffic. --------- Co-authored-by: Rudimar Ronsoni <6081613+rudironsoni@users.noreply.github.com> |
||
|
|
c65e321ea2
|
ci: bump the uv group across 1 directory with 5 updates (#1020)
Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore <dependency name> major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore <dependency name> minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore <dependency name>` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore <dependency name>` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore <dependency name> <ignore condition>` will remove the ignore condition of the specified dependency and ignore conditions You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/chopratejas/headroom/network/alerts). </details> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
27befef694
|
ci: bump the uv group across 1 directory with 17 updates (#832)
Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency - `@dependabot ignore <dependency name> major version` will close this group update PR and stop Dependabot creating any more for the specific dependency's major version (unless you unignore this specific dependency's major version or upgrade to it yourself) - `@dependabot ignore <dependency name> minor version` will close this group update PR and stop Dependabot creating any more for the specific dependency's minor version (unless you unignore this specific dependency's minor version or upgrade to it yourself) - `@dependabot ignore <dependency name>` will close this group update PR and stop Dependabot creating any more for the specific dependency (unless you unignore this specific dependency or upgrade to it yourself) - `@dependabot unignore <dependency name>` will remove all of the ignore conditions of the specified dependency - `@dependabot unignore <dependency name> <ignore condition>` will remove the ignore condition of the specified dependency and ignore conditions You can disable automated security fix PRs for this repo from the [Security Alerts page](https://github.com/chopratejas/headroom/network/alerts). </details> Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> |
||
|
|
9579567b7d
|
chore(deps): loosen over-pinned constraints and add upper bounds (#538)
## What Loosen over-pinned Python dependency constraints and add missing upper bounds in `pyproject.toml`. Also bump the neo4j Docker image and uv builder version. ## Why Several dependencies had constraints that either blocked security patches or allowed silent major-version jumps: - `litellm==1.82.3` was an exact pin — every security patch release requires a manual lockfile bump - `transformers`, `sentence-transformers` had no upper bound and have already crossed major version boundaries without a constraint gate - `neo4j>=5.20.0` had no upper cap; the driver has already reached 6.x in the wild - `mem0ai>=0.1.100` had a pre-1.0 floor while the locked version is already 1.0.11 - `langchain-core`, `langchain-openai`, `qdrant-client`, `uvicorn` had no upper bound on a range with active major-version churn - `docker-compose.yml` pinned neo4j at `5.15.0`, which is 11 patch releases behind the current 5.x LTS - `Dockerfile` pinned uv at `0.11.16`; latest stable is `0.11.18` ## How Constraint changes only — no code changes, no `uv lock --upgrade`. The existing locked versions all satisfy the new bounds (we added caps, not floors). `uv` re-resolved the lockfile to format revision 3 (adds `upload-time` metadata fields) and cleaned up the defunct `llmlingua` extra entries. | Dependency | Before | After | |---|---|---| | `litellm` | `==1.82.3` | `>=1.82.3,<2.0` | | `transformers` | `>=4.30.0` | `>=4.30.0,<6.0` | | `sentence-transformers` | `>=2.2.0` | `>=2.2.0,<6.0` | | `neo4j` | `>=5.20.0` | `>=5.20.0,<7.0` | | `mem0ai` | `>=0.1.100` | `>=1.0.0,<2.0` | | `langchain-core` | `>=0.2.0` | `>=0.2.0,<4.0` | | `langchain-openai` | `>=0.1.0` | `>=0.1.0,<2.0` | | `qdrant-client` | `>=1.9.0` | `>=1.9.0,<2.0` | | `uvicorn` | `>=0.23.0` | `>=0.23.0,<1.0` | | neo4j Docker image | `5.15.0` | `5.26` | | uv (Dockerfile ARG) | `0.11.16` | `0.11.18` | ## Breaking changes None. All currently installed versions fall within the new ranges. Installers that previously resolved `litellm` to an older exact pin may now resolve newer patch releases — which is the desired behavior. --------- Co-authored-by: Tejas Chopra <chopratejas@gmail.com> |
||
|
|
fa558c5647
|
fix(deps): move gunicorn to [proxy-prod] extra, add Windows guard (#537)
* fix(deps): add missing runtime deps to [code] and [proxy] extras - Add gunicorn>=21.0.0 to the [proxy] extra The proxy docs (docs/content/docs/proxy.mdx and wiki/proxy.md) show gunicorn as the recommended production deployment server: pip install gunicorn gunicorn headroom.proxy.server:app --worker-class uvicorn.workers.UvicornWorker Users installing headroom-ai[proxy] for production get uvicorn (already declared) but had to discover and install gunicorn manually. Adding it to [proxy] removes that friction. Investigation notes: - [code] only needs tree-sitter-language-pack (already declared). code_compressor.py has zero numpy imports. The kompress fallback inside code_compressor.py is guarded by ImportError and requires [ml]. - numpy is correctly declared in [relevance] (numpy>=1.24.0) and pulled transitively by sentence-transformers in [memory]. It is NOT needed under [code]. - tree-sitter is a transitive dep of tree-sitter-language-pack (requires tree-sitter>=0.25.2) so it does not need an explicit entry. * docs(changelog): add entry for gunicorn proxy dep fix style(tests): ruff format test_provider_proxy_routes.py (blank lines after docstrings) * fix(deps): move gunicorn to [proxy-prod] extra, add Windows guard - Remove gunicorn from [proxy] so dev, CI, and Windows users are not forced to install a Unix-only package that does nothing on Windows - Add new [proxy-prod] extra that includes [proxy] + gunicorn with a sys_platform != 'win32' environment marker - Production users: pip install 'headroom-ai[proxy,proxy-prod]' - Update CHANGELOG to reflect the new extra name * fix(devcontainer): bump uv floor to >=0.11.0 for lockfile compatibility uv 0.6.17 (previously pinned) cannot parse lockfiles generated by uv >= 0.11.x. The validate CI job (triggered by pyproject.toml changes) was failing with 'Failed to parse uv.lock'. Loosening the pin to >=0.11.0 picks up the matching format parser while keeping the Docker layer cacheable with a range rather than an exact pin. * fix(devcontainer): skip gitpython wheel filename check in uv sync gitpython 3.1.47 on PyPI has wheel gitpython-3.1.46-py3-none-any.whl (wrong filename). uv >=0.11.19 strict filename validation rejects this lockfile entry. UV_SKIP_WHEEL_FILENAME_CHECK=1 bypasses the check until the upstream lockfile is regenerated with a corrected entry. * fix(deps): correct gitpython version in uv.lock to match actual wheel gitpython 3.1.47 on PyPI was uploaded with sdist/wheel files named gitpython-3.1.46.*. The version field in uv.lock said 3.1.47 but all download URLs reference 3.1.46 files, causing uv >=0.11.19 to refuse to parse the lockfile with a version-mismatch error. Change the version field to 3.1.46 so the entry is internally consistent. Also revert the now-unnecessary UV_SKIP_WHEEL_FILENAME_CHECK workaround from post-create.sh. --------- Co-authored-by: Tejas Chopra <chopratejas@gmail.com> |
||
|
|
07581b9e80 | Fix: Upgrade litellm to 1.86.2 to remediate CVE-2026-42271 | ||
|
|
e325d1b866 |
fix(ci): pin public PyPI in pyproject.toml + scrub Netflix URLs from uv.lock
Devcontainer validate jobs were failing on PR #360 with: × Failed to fetch: https://pypi.netflix.net/packages/.../nvidia_nvshmem_cu12-3.4.5-...whl ├─▶ Request failed after 3 retries ╰─▶ operation timed out `pypi.netflix.net` is Netflix's internal PyPI mirror. It got into the lockfile because my local `~/.config/uv/uv.toml` had: index-url = "https://pypi.netflix.net/simple" Running `uv lock` from that machine baked Netflix-internal URLs into uv.lock for every package. Public CI runners (and any external contributor) can't resolve them. Two fixes: 1. Add `[[tool.uv.index]]` block to pyproject.toml pinning public PyPI as the project's default index. uv now ignores user-level config when resolving for this project, regardless of who runs `uv lock`. This prevents the same contamination from any developer in the future. 2. Regenerate uv.lock against public PyPI. All package URLs now point at `https://files.pythonhosted.org/...` and `https://pypi.org/simple/`. Zero references to `pypi.netflix.net` remain in the lockfile. Verified: `grep -c "pypi.netflix" uv.lock` returns 0. |
||
|
|
2a91cbb4b4 |
refactor: single-wheel maturin build backend (fixes #355)
Eliminates the dual-package architecture that was the root cause of #355. `pip install headroom-ai` now produces ONE wheel containing both the Python source (headroom/*.py) and the compiled Rust extension (headroom/_core.so). No more separate `headroom-core-py` package, no more chicken-and-egg with PyPI publication, no more wheelhouse / PIP_FIND_LINKS / composite-action plumbing in CI. This is the canonical pattern used by cryptography, polars, ruff, pydantic-core, and other Rust-as-core Python packages. Honors the "Rust as core engine" direction. ## What changed - pyproject.toml: `[build-system]` swapped from hatchling to maturin. `[tool.hatch.*]` deleted; `[tool.maturin]` added pointing at `crates/headroom-py/Cargo.toml` for the cdylib. `python-source = "."` picks up the root `headroom/` package directly (dashboard HTML templates and other non-Python files included automatically). - crates/headroom-py/pyproject.toml: deleted. The crate is no longer a separate published package; its Cargo.toml stays as the cdylib build target invoked via `[tool.maturin] manifest-path`. - crates/headroom-py/python/: deleted (placeholder layout for the old separate package). ## CI updates - ci.yml: `test` / `test-extras` / `test-agno` jobs simplified — Rust toolchain set up before `pip install -e .` (which now invokes maturin via build-system). Removed the "build wheel + symlink .so" dance. `build` job swapped from `python -m build` (hatch) to `maturin build` + `maturin sdist`. - release.yml: collapsed dual-package matrix into one. New `build-wheels` matrix produces cross-platform wheels for cp310/11/12/13 × {linux x86_64, linux aarch64, macos x86_64, macos aarch64}. New `collect-dist` aggregator merges artifacts. publish-pypi consumes the merged dist. - init-native-e2e.yml: dropped windows-latest from the matrix — upstream `esaxx-rs` (/MT) and `ort-sys` (/MD) link with conflicting MSVC C runtime libraries, so the Rust extension cannot build for win_amd64 today. Tracked as a follow-up; not a blocker for Linux+macOS. - headroom-e2e-setup: composite action now sets up Rust toolchain + Swatinem/rust-cache before `pip install -e .[proxy]`. - eval.yml, publish.yml, rust.yml: same pattern — rust toolchain before install. rust.yml's wheels job builds from root pyproject.toml (no more `-m crates/headroom-py/Cargo.toml`). - e2e/init/Dockerfile, e2e/wrap/Dockerfile: install rust + maturin in the build stage; copy `crates/` + workspace `Cargo.toml/lock` so the install can build the extension. Dropped `HEADROOM_REQUIRE_RUST_CORE=false` from wrap-e2e — the image now ships the full Rust core. - Dockerfile (main): simplified — no more Layer 2/3 dance with `headroom-core-py` install + symlink. Single `uv pip install` builds + installs everything. - .devcontainer/Dockerfile: rust toolchain + libssl-dev + maturin added so `uv sync` builds the extension inside the devcontainer. ## Lockfile + script - uv.lock: regenerated. No `headroom-core-py` entries remain. - scripts/build_rust_extension.sh: simplified from a symlink-into-tree workaround to a thin wrapper around `pip install -e .`. The maturin build-backend handles placement automatically. ## Local validation (all green on macOS aarch64) 1. Clean venv `pip install -e .` → `from headroom._core import …` works. 2. `maturin build --release` → 13.8 MB wheel, 336 files including `headroom/_core.cpython-311-darwin.so` (32 MB cdylib) and `headroom/dashboard/templates/dashboard.html`. 3. `pip install <wheel>` in fresh venv → import works. 4. Wheel contents verified via `unzip -l`. 5. `pytest tests/test_transforms/test_diff_compressor.py` — 29 passed. 6. `pytest tests/test_relevance.py` — 30 passed. 7. `cargo build --workspace` + `cargo test --workspace` — all green. 8. `make ci-precheck` — 176 Python tests + Rust + commitlint green. ## Migration notes Users on `pip install headroom-ai` get the Rust core automatically (linux + macos wheels). sdist installs require rust toolchain available locally — pip will build via maturin. Closes #355 Supersedes #357 (workarounds-based fix abandoned in favor of architectural fix) |
||
|
|
ce3b2f0b0b |
fix(ci): regenerate uv.lock against public PyPI (was Netflix-internal)
The validate × 3 devcontainer CI failures were NOT environmental —
they were caused by this branch.
Root cause: commit
|
||
|
|
967b0db439 |
fix: B1 — retire ICM, RollingWindow, scoring, relevance + dependents
Phase B step 1 of the live-zone-only realignment. Removes ~10K LOC of
"drop messages from history" machinery that became unreachable after
PR-A1 made `/v1/messages` a passthrough on the proxy. Live-zone-only
compression (PR-B2..B7) operates on content blocks within messages;
message-list mutation no longer happens in the pipeline.
Python deletes:
- headroom/transforms/intelligent_context.py (1077 LOC)
- headroom/transforms/rolling_window.py (395 LOC)
- headroom/transforms/progressive_summarizer.py (508 LOC)
- headroom/transforms/scoring.py (459 LOC)
- headroom/transforms/tool_crusher.py (338 LOC)
- 5 corresponding tests/test_transforms/* and tests/test_proxy_intelligent_context.py
Rust deletes:
- crates/headroom-core/src/context/* (manager, config, workspace,
candidate, ccr_drop, strategy/, mod) + safety.rs replaced
- crates/headroom-core/src/scoring/* (mod, score, scorer, traits, weights)
- MessageScorerComparator from crates/headroom-parity (PR #338/#343
becomes deletable; sunk cost stays sunk)
- 13 message_scorer fixtures + record_message_scorer.py
Rust adds (move + rewrite):
- crates/headroom-core/src/transforms/safety.rs — `tool_pair_indices`
preserves the OpenAI/Anthropic tool_use ↔ tool_result pairing rule
the live-zone dispatcher (PR-B2) needs. No IcmConfig dependency.
Surface refactors:
- HeadroomConfig: drop `tool_crusher`, `rolling_window`,
`intelligent_context` fields; hoist `output_buffer_tokens` to top
level (used by client.py).
- ProxyConfig: drop `intelligent_context*` fields.
- `headroom wrap` proxy server: retire IntelligentContextManager
and RollingWindow imports + branch; pipeline is CacheAligner →
ContentRouter (smart_routing) or CacheAligner → SmartCrusher
(legacy).
- CLI: drop `--no-intelligent-context`, `--no-intelligent-scoring`,
`--no-compress-first` flags.
- LangChain memory integration: rename `_apply_rolling_window` →
`_apply_compression`, drop RollingWindowConfig dep. Threshold is
now advisory — B6 will rework the contract.
- TransformPipeline.create_pipeline now takes only cache_aligner_config.
- headroom/__init__.py + headroom/transforms/__init__.py: strip
exports of deleted symbols.
Bug fixes uncovered by full pytest sweep:
- providers/copilot/wrap.py: `environ or os.environ` collapsed
empty-dict to falsy → callers passing `environ={}` accidentally
pulled from os.environ. Use `environ if environ is not None else
os.environ`.
Test correctness fixes:
- _DummyAnthropicHandler._retry_request gains **_kwargs to match
the real handler signature post-A8.
- test_ws_http_fallback extracts JSON from `content=` (post-A3
byte-faithful) rather than the obsolete `json=` kwarg.
- test_ccr_response_handler_extra fixture joins SSE events with
`\n\n` per spec (post-A8 byte-buffer parser requirement).
- test_proxy_responses_phase_preservation: capture via direct
handler attached to the named logger, so the assertion is
order-independent (proxy `_setup_file_logging` flips
`headroom.propagate=False` once any earlier test triggers it).
- conftest.py autouse fixture resets `headroom.propagate=True`
before each test as a defensive measure for the same pollution.
- test_wrap_copilot_translated_backend_still_requires_byok:
monkeypatch.delenv every provider key so the BYOK error
actually fires.
- test_native_installers: skip when system bash < 4.3 (macOS ships 3.2).
- TestGeminiEmbedContent / TestGeminiBatchEmbedContents:
pytest.mark.skip — proxy currently has no :embedContent route;
feature gap, not regression.
Acceptance:
- cargo build --workspace + cargo clippy + cargo fmt --check: green.
- cargo test --workspace --exclude headroom-py: 777 passed.
- pytest: 4892 passed, 240 skipped, 0 failed.
- git grep returns only intentional comments referencing the deletion.
Per-PR-B1 plan: REALIGNMENT/04-phase-B-live-zone.md.
|
||
|
|
e25f5515ab
|
chore(deps): bump nltk in the uv group across 1 directory
Bumps the uv group with 1 update in the / directory: [nltk](https://github.com/nltk/nltk). Updates `nltk` from 3.9.2 to 3.9.4 - [Changelog](https://github.com/nltk/nltk/blob/develop/ChangeLog) - [Commits](https://github.com/nltk/nltk/compare/3.9.2...3.9.4) --- updated-dependencies: - dependency-name: nltk dependency-version: 3.9.4 dependency-type: indirect dependency-group: uv ... Signed-off-by: dependabot[bot] <support@github.com> |
||
|
|
b71b659e1b
|
fix(ci): restore repro harness test in dev installs
Add websockets to the dev extra so the repro harness smoke test can import its websocket client dependency in the CI test matrix. Also apply ruff formatting to the files the formatter check was rejecting so the 3.12 lint job passes. |
||
|
|
6bc44b3e00
|
chore(deps): refresh uv.lock to schema revision 3
Upgrade of the local uv CLI rewrote the lock file with `revision = 3` and renamed the metadata key `upload_time` -> `upload-time`. No actual dependency version changes. |
||
|
|
a1beb08d53 |
feat: add reproducible devcontainers
Add a default devcontainer and a compose-backed memory-stack profile, validate them in CI, and document the contributor workflow. Also lock the memory-stack dependencies, pin related container tooling, and sync the latest healthcheck shutdown fix for stubbed memory handlers. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> |
||
|
|
7d02829f02 | Harden Anthropic prefix cache stability across proxy and batch paths | ||
|
|
40369762dd |
Add Cloud mode to ASGI middleware and LiteLLM callback
Both CompressionMiddleware and HeadroomCallback now support a cloud mode (api_key="hdr_xxx") that calls Headroom Cloud API for managed compression with org-scoped CCR, TOIN learning, and analytics. Falls back to HEADROOM_API_KEY env var. Local mode (default) is unchanged. Also adds x-headroom-tokens-before/after response headers and updates uv.lock with mcp extra and version bump to 0.3.3. |
||
|
|
84ad47eba9 |
Add SQLiteVectorIndex using sqlite-vec for bounded vector search
A SQLite-based alternative to HNSWVectorIndex offering: - True CRUD operations (real deletes, not marks) - Bounded memory via SQLite page cache (default 8MB) - Persistent storage by default - Cosine similarity search - Native integration potential with FTS5 for hybrid search New files: - headroom/memory/adapters/sqlite_vector.py: Implementation - tests/test_sqlite_vector_index.py: 16 comprehensive tests Dependencies: - sqlite-vec added as optional dependency (pip install sqlite-vec) - Requires Python built with loadable extension support Key advantages over HNSWVectorIndex: - No SIGILL crash risk (pure C, no AVX requirement) - True deletes (not just marks, space actually reclaimed) - Simpler persistence (SQLite handles it automatically) - Consistent with SQLiteGraphStore (same technology stack) |
||
|
|
e86d9a396e |
feat(compression): add exclude_tools to bypass compression for specific tools
Add ability to exclude specific tools from compression, useful for CLI tools like Claude Code where file/search output should be passed through unmodified. Changes: - Add DEFAULT_EXCLUDE_TOOLS constant with Read, Grep, Glob, Bash, WebFetch, WebSearch - Add exclude_tools field to SmartCrusherConfig and ContentRouterConfig - Add _build_tool_name_map() to ContentRouter for tool_call_id -> name mapping - Skip compression for tool_result blocks from excluded tools - Support both Anthropic (tool_use/tool_result) and OpenAI (tool_calls/tool) formats This prevents Headroom from compressing output from tools where the user expects to see the full, unmodified content (e.g., file reads, search results). Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> |
||
|
|
d1a28322cc |
Add HTMLExtractor for web content extraction with OSS benchmarks
HTMLExtractor uses trafilatura to extract main content from HTML pages, removing scripts, styles, navigation, and ads. This achieves 94.9% compression while preserving 98.2% recall on the Scrapinghub benchmark. Key features: - Automatic HTML detection in content router - Configurable output format (markdown or text) - Metadata extraction (title, author, date, description) - Batch extraction support Evaluation framework: - OSS benchmark integration (Scrapinghub Article Extraction Benchmark) - LLM-as-judge evaluation for QA accuracy preservation - F1 score: 0.919 on 181-sample benchmark (baseline: 0.958) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> |
||
|
|
9825d993ba |
feat: add streaming memory tool support with credential error handling
- Implement streaming memory tool detection and execution for Anthropic API - Buffer SSE response to detect tool_use blocks, execute tools, and stream continuation - Add helpful error detection and messaging for subscription credential restrictions - Add startup note when memory tools enabled warning about API key requirement - Move hnswlib to core dependencies for memory system - Update CLI to show memory tool/context status on startup |