Commit graph

9 commits

Author SHA1 Message Date
Tejas Chopra
1cc99792ac
fix(version): mark source-checkout builds as -dev (#2072)
## Description

`headroom --version` and the dashboard show `0.32.0` from a source
checkout, but the latest published release is `0.31.0`. That `0.32.0` is
not a real release: on a git checkout `get_version()` predicts the
*next* release from conventional commits since the last tag (`v0.31.0` +
`feat:` commits → `0.32.0`) and renders it identically to a shipped
version — so a dev build looks published.

This appends `-dev` on the source-checkout path so a dev build is never
mistaken for the published release.

Closes #

## Type of Change

- [x] Bug fix (non-breaking change that fixes an issue)

## Changes Made

- `headroom/_version.py`: the source-checkout branch of `get_version()`
now returns `f"{source_version}-dev"`.
- `tests/test_package_init_lazy.py`: updated the source-tree version
test to assert the `-dev` suffix.

Released installs are unaffected: pip wheels and Docker images with a
baked `BUILD_VERSION` never take the source-checkout path, so they still
report clean release versions (`0.31.0` / `v0.31.0`). The suffix makes
`is_release_version()` return `False` and `normalize_release_version()`
return `None`, which every comparison site already handles — e.g.
`wrap.py`'s `_proxy_needs_version_restart` requires both sides to
normalize, so a dev build short-circuits to "no restart" (no behavior
change).

## Testing

- [x] Unit tests pass (`pytest`)
- [x] Linting passes (`ruff check .`)
- [x] Type checking passes (`mypy headroom`)
- [x] New tests added for new functionality (updated the existing
source-tree test)
- [x] Manual testing performed

### Test Output

```text
$ python -m pytest tests/test_package_init_lazy.py tests/test_cli_doctor.py -q
============================== 12 passed in 1.79s ==============================
============================== 51 passed in 0.56s ==============================

$ ruff check headroom/_version.py tests/test_package_init_lazy.py
All checks passed!

$ mypy headroom/_version.py
Success: no issues found in 1 source file
```

## Real Behavior Proof

- Environment: local source checkout (macOS), `.venv`, latest release
tag `v0.31.0`
- Exact command / steps: `headroom --version`
- Observed result:
- Before: `headroom, version 0.32.0` — indistinguishable from a release
  - After: `headroom, version 0.32.0-dev`
- Not tested: behavior inside a built Docker image / installed pip wheel
— unchanged by design, since those paths never compute a source-tree
version.

## 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

## Additional Notes

Scope kept to a bare `-dev` marker, which answers "is this a release?".
Appending the short git SHA (`-dev+g<sha>`) to distinguish individual
dev builds in bug reports is an easy follow-up if wanted. Docs/CHANGELOG
unchecked as N/A for a dev-only version-string fix.

---------

Co-authored-by: JerrettDavis <mxjerrett@gmail.com>
2026-07-13 09:38:17 -04:00
JD Davis
e6243f65c9
refactor(providers): split proxy route adapters (#1934)
## Description
Refactors provider-specific proxy routing into provider-owned helper
modules so `headroom/providers/proxy_routes.py` primarily registers
routes and delegates behavior. This keeps Codex, OpenAI
Responses/images, model metadata, Vertex, Cloud Code, passthrough target
selection, and request path normalization logic testable outside the
route table.

Closes #

## Type of Change
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing
functionality to not work as expected)
- [ ] Documentation update
- [ ] Performance improvement
- [x] Code refactoring (no functional changes)

## Changes Made
- Extracted Codex routing helpers for headers, endpoint URLs, image
forwarding, response subpaths, and model metadata.
- Moved provider target selection, route specs, OpenAI Responses/images
helpers, Vertex runtime helpers, Cloud Code path normalization,
passthrough telemetry, and request scope normalization into focused
modules.
- Kept `proxy_routes.py` as route registration/delegation and preserved
current-main `/v1/messages` custom-base behavior.
- Added focused provider/proxy tests for the extracted modules and route
delegation behavior.

## 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
python -m pytest tests/test_package_init_lazy.py::test_codex_package_import_stays_runtime_only tests/test_provider_cloudcode_runtime.py tests/test_provider_codex_endpoints.py tests/test_provider_codex_headers.py tests/test_provider_codex_images.py tests/test_provider_codex_model_metadata.py tests/test_provider_codex_responses.py tests/test_provider_model_metadata.py tests/test_provider_openai_images.py tests/test_provider_openai_responses.py tests/test_provider_proxy_targets.py tests/test_provider_route_specs.py tests/test_provider_vertex_runtime.py tests/test_proxy_request_scope.py tests/test_provider_proxy_routes.py::test_provider_passthrough_routes_forward_expected_targets tests/test_provider_proxy_routes.py::test_proxy_route_helpers_prefer_legacy_targets_and_gemini_passthrough tests/test_provider_proxy_routes.py::test_provider_specific_routes_delegate_to_expected_proxy_handlers tests/test_provider_proxy_routes.py::test_openai_response_websocket_aliases_delegate_to_openai_ws_handler tests/test_provider_proxy_routes.py::test_openai_response_subpath_passthrough_returns_502_on_http_failure tests/test_provider_proxy_routes.py::test_openai_response_subpath_passthrough_uses_openai_target tests/test_provider_proxy_routes.py::test_openai_response_subpath_aliases_and_chatgpt_auth_use_expected_targets tests/test_provider_proxy_routes.py::test_openai_image_routes_use_codex_backend_under_chatgpt_auth tests/test_provider_proxy_routes.py::test_openai_image_codex_response_strips_stale_compression_headers tests/test_provider_proxy_routes.py::test_openai_image_edits_api_key_auth_falls_through_to_openai_passthrough tests/test_provider_proxy_routes.py::test_openai_image_edits_preserves_multipart_body_under_chatgpt_auth tests/test_provider_proxy_routes.py::test_gemini_batch_embed_contents_passthrough_uses_gemini_target tests/test_provider_proxy_routes.py::test_v1_models_fetches_codex_registry_under_chatgpt_auth tests/test_provider_proxy_routes.py::test_v1_models_falls_back_to_synthetic_list_under_chatgpt_auth tests/test_provider_proxy_routes.py::test_v1_models_get_single_dynamic_under_chatgpt_auth tests/test_provider_proxy_routes.py::test_v1_models_still_forwards_under_non_chatgpt_auth tests/test_provider_proxy_routes.py::test_v1_models_routes_claude_code_gateway_discovery_to_anthropic tests/test_provider_proxy_routes.py::test_anthropic_model_metadata_strips_ansi_model_ids tests/test_custom_base_passthrough_telemetry.py tests/test_proxy_passthrough.py tests/test_proxy_google_cloudcode_route_aliases.py tests/test_proxy_project_savings.py::test_with_project_prefix_round_trips_through_split tests/test_vertex_claude_compression.py
============================ 102 passed in 34.83s =============================

python -m ruff check headroom/providers/cloudcode headroom/providers/codex headroom/providers/vertex headroom/providers/model_metadata.py headroom/providers/openai_images.py headroom/providers/openai_responses.py headroom/providers/proxy_targets.py headroom/providers/route_specs.py headroom/providers/proxy_routes.py headroom/proxy/handlers/openai.py headroom/proxy/passthrough.py headroom/proxy/request_scope.py headroom/proxy/project_context.py tests/test_package_init_lazy.py tests/test_provider_cloudcode_runtime.py tests/test_provider_codex_endpoints.py tests/test_provider_codex_headers.py tests/test_provider_codex_images.py tests/test_provider_codex_model_metadata.py tests/test_provider_codex_responses.py tests/test_provider_model_metadata.py tests/test_provider_openai_images.py tests/test_provider_openai_responses.py tests/test_provider_proxy_targets.py tests/test_provider_route_specs.py tests/test_provider_vertex_runtime.py tests/test_proxy_request_scope.py tests/test_provider_proxy_routes.py tests/test_custom_base_passthrough_telemetry.py tests/test_proxy_passthrough.py tests/test_proxy_google_cloudcode_route_aliases.py tests/test_proxy_project_savings.py tests/test_vertex_claude_compression.py
All checks passed!

python -m compileall -q headroom\providers\cloudcode headroom\providers\codex headroom\providers\vertex headroom\providers\model_metadata.py headroom\providers\openai_images.py headroom\providers\openai_responses.py headroom\providers\proxy_targets.py headroom\providers\route_specs.py headroom\providers\proxy_routes.py headroom\proxy\handlers\openai.py headroom\proxy\passthrough.py headroom\proxy\request_scope.py headroom\proxy\project_context.py
# no output; exited 0

git commit -m "refactor(providers): split proxy route adapters"
Sync plugin versions.....................................................Passed
check for merge conflicts................................................Passed
ruff.....................................................................Passed
ruff-format..............................................................Passed
mypy.....................................................................Passed
```

## Real Behavior Proof
- Environment: Windows PowerShell, Python 3.13.13, branch
`jd/provider-route-slices` based on `headroomlabs/main`.
- Exact command / steps: Ran the focused provider/proxy pytest suite,
focused ruff command, compileall over changed Python modules, and commit
hooks.
- Observed result: Provider/proxy route behavior tests passed; lint,
formatting, and mypy passed.
- Not tested: Full pytest suite, live upstream provider calls, and
manual end-to-end proxy traffic.

## 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)
N/A

## Additional Notes
Documentation and CHANGELOG updates are N/A for this internal refactor.
The full pytest suite was not run; coverage here is focused on
provider/proxy routing behavior touched by this slice.

---------

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
2026-07-12 16:27:45 -05:00
Vinay Gupta
38074888ac
fix(docker): report source build version (#1862)
## Description

Closes #1858

Docker/Compose source builds could report stale or misleading version
information: the dashboard initially rendered a hardcoded `v0.3.0`, then
`/health` replaced it with installed package metadata, which can be
stale when building locally from `main` without release metadata in the
image.

This change makes source Docker Compose builds report an explicit
source-build identity, removes the stale dashboard fallback, and keeps
CLI/doctor version checks from treating source-build labels as
release-version drift.

## 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

- Add `HEADROOM_VERSION` / `HEADROOM_BUILD_VERSION` runtime version
overrides and optional packaged `_build_info.py` metadata.
- Teach Docker Compose source builds to pass a `source-build` sentinel
that the Dockerfile expands to `source-build+g<sha>` when git metadata
is available, or `source-build+sha256.<digest>` otherwise.
- Keep release/published image builds on normal package metadata when
`HEADROOM_BUILD_VERSION` is unset.
- Include only minimal `.git` metadata in the Docker build context so
the source-build label can identify the checkout without copying git
objects.
- Treat source-build labels and raw hashes as non-release labels in
`wrap` and `doctor`, avoiding false stale-proxy restarts and drift
warnings.
- Replace the dashboard hardcoded `0.3.0` fallback with `loading` /
`unknown` and format non-release build labels without a `v` prefix.
- Include the runtime version in proxy startup logs, `/health`,
`/livez`, and OTEL service version reporting.

## Testing

- [x] Unit tests pass (`pytest` in GitHub CI)
- [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
GitHub CI: all checks passing
- CI: build, build-wheel, lint, test shards, test-extras, test-agno, test-dashboard-ui
- Docker: docker-native-e2e, docker-wrap-e2e, docker-init-e2e
- Native wrappers: macOS, Windows, Ubuntu
- Security: CodeQL, gitleaks, pip-audit
- Governance: template, label, merge-conflicts, commitlint

$ HEADROOM_REQUIRE_RUST_CORE=false PYTHONPATH=/Users/vinaygupta/Desktop/git/headroom-fix-1858-version-mismatch pytest tests/test_package_init_lazy.py::test_version_prefers_explicit_build_env tests/test_package_init_lazy.py::test_version_label_helpers_only_prefix_release_versions tests/test_package_init_lazy.py::test_version_uses_packaged_build_metadata tests/test_package_init_lazy.py::test_observability_version_uses_runtime_version tests/test_docker_compose_persistence.py tests/test_cli_doctor.py::TestProxyLiveness::test_up_leaves_source_label_unprefixed tests/test_cli_doctor.py::TestVersionDrift::test_non_release_version_labels_skip_drift_comparison tests/test_cli/test_wrap_persistent.py::test_proxy_version_restart_ignores_non_release_source_labels tests/test_proxy_dashboard_stats_cache.py::test_dashboard_uses_cached_stats_and_lazy_history_feed_polling -q
13 passed, 1 warning

$ uvx ruff==0.15.17 check .
All checks passed!

$ uvx ruff==0.15.17 format --check .
1058 files already formatted

$ uvx mypy==1.20.2 headroom --ignore-missing-imports
Success: no issues found in 407 source files

$ git diff --check
# no output

$ docker compose config
# resolved headroom-proxy build args include HEADROOM_BUILD_VERSION: source-build

$ HEADROOM_BUILD_VERSION=6266a1d docker compose config
# explicit override is preserved as HEADROOM_BUILD_VERSION: 6266a1d

$ docker build --check --build-arg HEADROOM_BUILD_VERSION=source-build .
Check complete, no warnings found.
```

## Real Behavior Proof

- Environment: macOS local checkout, Python 3.13.5, Docker Desktop
builder `desktop-linux`, plus GitHub Actions CI.
- Exact command / steps: `docker compose config`,
`HEADROOM_BUILD_VERSION=6266a1d docker compose config`, and `docker
build --check --build-arg HEADROOM_BUILD_VERSION=source-build .`.
- Observed result: Compose defaults the top-level `headroom-proxy` build
arg to the `source-build` sentinel, preserves explicit overrides, and
Dockerfile syntax/check validation passes for the source-build path.
- Not tested: Full end-to-end release publishing flow; this PR only
changes local/source-build reporting.
- CI proof: GitHub Actions completed successfully across Docker E2E, CI
test shards, lint/type checks, native wrapper checks, security checks,
and PR governance.

## 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/CI with my changes
- [ ] I have updated the CHANGELOG.md if applicable

## Screenshots (if applicable)

N/A

## Additional Notes

Docs and changelog are N/A for this runtime-reporting bug fix. The PR is
open and ready for review with all GitHub checks passing.
2026-07-08 13:32:04 -05:00
Parideboy
3ccdad6c67
Pin ORT dylib on Windows; init Python logging (#1010)
## Description

On Windows, headroom's Rust core resolves `onnxruntime.dll` at runtime
via `ort-load-dynamic`. Without an explicit `ORT_DYLIB_PATH`, the bare
DLL search can land on `C:\Windows\System32\onnxruntime.dll`, the
Windows ML OS component, and `Session::new()` can deadlock instead of
returning an error. Since a hang is not an `Err`, the tiered fallback
cannot engage until the proxy-level timeout fires.

This PR pins `ORT_DYLIB_PATH` to the pip-installed `onnxruntime` DLL at
import time, and wires Rust `tracing` events into Python logging so the
proxy log surfaces these failures when they occur.

Closes #928

## 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

- Added `headroom/_ort.py` with a Windows-only, idempotent
`ensure_ort_dylib_pinned()` resolver that respects an existing
`ORT_DYLIB_PATH`.
- Call the pin from `headroom/__init__.py` before importing `_core`
consumers.
- Log the effective ORT dylib path from the content router startup path
on Windows.
- Enable Rust tracing-to-log compatibility and initialize `pyo3-log` in
the `_core` module.
- Add timeout diagnostics in the Magika detector with the effective
`ORT_DYLIB_PATH`.
- Document `ORT_DYLIB_PATH` and `HEADROOM_MAGIKA_INIT_TIMEOUT_SECS`.
- Add unit coverage for the resolver behavior.

## Testing

- [x] Unit tests pass (`python -m pytest
tests/test_transforms/test_ort_dylib.py -q`)
- [x] Linting passes (`ruff check headroom/_ort.py headroom/__init__.py
headroom/transforms/content_router.py
tests/test_transforms/test_ort_dylib.py`)
- [x] Formatting passes (`ruff format --check headroom/_ort.py
headroom/__init__.py headroom/transforms/content_router.py
tests/test_transforms/test_ort_dylib.py`)
- [x] New tests added for new functionality
- [x] Manual testing performed

### Test Output

```text
$ python -m pytest tests/test_transforms/test_ort_dylib.py -q
7 passed in 0.19s

$ ruff check headroom/_ort.py headroom/__init__.py headroom/transforms/content_router.py tests/test_transforms/test_ort_dylib.py
All checks passed!

$ ruff format --check headroom/_ort.py headroom/__init__.py headroom/transforms/content_router.py tests/test_transforms/test_ort_dylib.py
4 files already formatted

$ cargo check -p headroom-py
cargo: The term 'cargo' is not recognized as a name of a cmdlet, function, script file, or executable program.
```

## Real Behavior Proof

- Environment: Windows 11 24H2, Python 3.13, RTX 4080
- Exact command / steps: `python -c "import headroom; from
headroom._core import detect_content_type as d;
print(d(open('headroom/compress.py').read()).content_type)"`
- Observed result: `source_code` in 301ms, clean exit, `Magika: ENABLED`
in proxy log
- Not tested: macOS/Linux manual runtime behavior; `_ort.py` is a no-op
outside Windows, and CI covers cross-platform build/test behavior.

## 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
- [ ] I have updated the CHANGELOG.md if applicable (N/A: repo uses
release-please)

## Additional Notes

The branch was rebased onto current `main` and the commit subject was
updated to satisfy commitlint. Local Rust verification could not be run
on this Windows machine because `cargo` is not installed; GitHub CI
should be treated as the Rust build verification for the `pyo3-log`
dependency and workspace lockfile changes.

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-23 07:46:24 -05:00
Zbl1007
e0a9fdb62c
chore(imports): lazy-load dynamic detector ML imports (#597)
## Description

Avoid importing optional ML dependencies when
`headroom.cache.dynamic_detector` is imported during wrap/proxy startup.
This keeps the dynamic detector module cheap to import while preserving
the existing NER and semantic detector behavior when those tiers are
actually used.

Fixes #195

## 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
- [x] Performance improvement
- [ ] Code refactoring (no functional changes)

## Changes Made

- Replaced eager `spacy`, `sentence_transformers`, and `numpy` imports
in `dynamic_detector.py` with `find_spec` availability checks.
- Kept NER and semantic model loading on the existing first-use detector
initialization paths.
- Moved `numpy` import to the semantic similarity calculation path where
it is actually needed.
- Added regression coverage proving `dynamic_detector` import does not
load optional ML modules even when stub versions of those modules are
importable.

## 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
.venv/bin/pytest tests/test_package_init_lazy.py
7 passed in 2.82s

.venv/bin/pytest tests/test_cache/test_dynamic_detector.py tests/test_package_init_lazy.py
43 passed, 2 skipped in 19.48s

.venv/bin/python -m ruff check headroom/cache/dynamic_detector.py tests/test_package_init_lazy.py
All checks passed!

.venv/bin/python -m ruff format --check headroom/cache/dynamic_detector.py tests/test_package_init_lazy.py
2 files already formatted

git diff --check
# no output
```

## Real Behavior Proof

- Environment: macOS local checkout, Python 3.11 virtualenv at `.venv`.
- Exact command / steps: Added a subprocess regression test that creates
importable stub `spacy`, `numpy`, `torch`, and `sentence_transformers`
modules, imports `headroom.cache.dynamic_detector`, and inspects
`sys.modules`.
- Observed result: Before the implementation change, the new regression
test failed because `spacy` was loaded during module import. After the
change, `spacy`, `sentence_transformers`, and `torch` remain unloaded
and the dynamic detector test suite still passes.
- Not tested: Full repository-wide `mypy headroom`; full CI requires
maintainer approval for fork workflows.

## 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

This branch has been narrowed after review feedback. It now only
contains the lazy `dynamic_detector` import fix. The wrapper
startup-timeout behavior was removed from this PR so it can be reviewed
separately from the existing timeout work.

Signed-off-by: Zbl1007 <1399853961@qq.com>
2026-06-13 10:50:42 -05:00
Andrew Rich
93c69372e6
fix(proxy): lazy-import server to avoid fastapi crash (#442)
## Summary

- Lazy-import `create_app`/`run_server` in `headroom/proxy/__init__.py`
via PEP 562 `__getattr__` to prevent CLI crash when `fastapi` is not
installed (i.e., installed without `[proxy]` extras)
- Fix `.pre-commit-config.yaml` to use `python3` instead of `python`
(unavailable on macOS Homebrew)
- Add graceful `ImportError` skip in `scripts/sync-plugin-versions.py`
for environments without dev dependencies

Fixes #441

## Test plan

- [x] `headroom --help` works without `[proxy]` extras installed
- [x] `headroom proxy --help` works with `[proxy]` extras installed
- [x] `headroom proxy --port 18787` starts and serves traffic
- [x] Lazy imports resolve correctly: `from headroom.proxy import
create_app, run_server`
- [x] `AttributeError` raised for invalid attributes on `headroom.proxy`
- [x] Pre-commit hooks pass (ruff, ruff-format, mypy,
sync-plugin-versions)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Code Bot <claude-code@smartwatermelon.github>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-10 12:44:23 -05:00
Tejas Chopra
ea1f608e79 fix: make proxy upgrades version-aware
Derive source-tree versions from release history so headroom --version no longer reports stale project metadata.

Restart stale idle proxies after an upgrade, but leave active sessions running to avoid interrupting ongoing conversations.

Remove _version.py from version-sync ownership and make version verification catch package/plugin manifest drift.
2026-05-09 15:58:27 -07:00
chopratejas
89061fd430 Fix CI lint errors and test failures
- test_memory_sync.py: remove unused imports (asyncio, MagicMock,
  AgentMemory, AgentMemoryAdapter, SyncResult), fix import sorting
- test_ws_memory_relay.py: remove unused pytest import and unused
  output_index variable, fix import sorting
- test_wrap_copilot.py: provide dummy API keys in test env — the
  BYOK validation added in 7a7b8b6 requires ANTHROPIC_API_KEY or
  OPENAI_API_KEY to be set
- test_package_init_lazy.py: stop hardcoding version string that
  breaks on every bump; assert it's a non-empty string instead

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 18:23:06 -07:00
JerrettDavis
f63cfe7a1e fix: lazy-load proxy startup dependencies
Keep the default Headroom proxy startup path lightweight so OpenClaw can launch it reliably on Windows. This defers heavyweight provider, cache, transform, pricing, and detector imports until they are actually needed, adds a lightweight version module, and keeps the OpenClaw launcher on the configured Python path.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-10 20:33:46 -05:00