mirror of
https://github.com/headroomlabs-ai/headroom.git
synced 2026-08-27 14:17:10 -04:00
## Description `_resolve_openai_upstream_base` ran the `X-Headroom-Base-Url` value through `_normalize_origin`, which strips the path. A custom OpenAI-compatible upstream served from a sub-path, such as `https://host/api/v1`, was routed to the bare origin and returned `proxy_error` (#2037). This re-attaches the path after origin normalization. This is a clean extraction of the path fix from #2047, which bundled it with an unrelated `supports_websockets = true` to `false` default change across init/wrap/codex. #2047 can be closed in favor of this narrower fix. Closes #2037 ## 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/handlers/openai.py`: re-attach the request header path component in `_resolve_openai_upstream_base` after origin normalization. - `tests/test_proxy/test_openai_upstream_header.py`: assert sub-paths are preserved and trailing slashes are normalized. ## 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 $ pytest tests/test_proxy/test_openai_upstream_header.py 5 passed $ ruff check headroom/proxy/handlers/openai.py tests/test_proxy/test_openai_upstream_header.py All checks passed! ``` ## Real Behavior Proof - Environment: local proxy header resolution path, custom OpenAI-compatible upstream configured via `X-Headroom-Base-Url`. - Exact command / steps: resolve `X-Headroom-Base-Url: https://gateway.example/api/v1` through `_resolve_openai_upstream_base` / `_resolve_openai_upstream`. - Observed result: before the fix, the upstream resolved to `https://gateway.example` and lost `/api/v1`, causing the proxy to route to the wrong endpoint. After the fix, it resolves to `https://gateway.example/api/v1`; a trailing slash is normalized away. - Not tested: end-to-end request against a live third-party OpenAI-compatible gateway. The regression is covered at the proxy routing helper layer where the path was dropped. ## 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 is not updated because this fixes the existing header behavior rather than changing a documented user-facing contract. - Changelog is not updated in this PR; the change is scoped to the regression and test. - `mypy headroom` was not run in the author's workflow. |
||
|---|---|---|
| .. | ||
| test_anthropic_buffered_timeout.py | ||
| test_anthropic_ccr_deferred_injection.py | ||
| test_anthropic_ccr_raise.py | ||
| test_anthropic_streaming_ccr_retrieve.py | ||
| test_anthropic_upstream_header.py | ||
| test_background_compression.py | ||
| test_bedrock_passthrough.py | ||
| test_cc_switch_reconciler.py | ||
| test_ccr_frozen_prefix_coupling.py | ||
| test_compression_failure_action.py | ||
| test_compression_timeout_config.py | ||
| test_compute_turn_id.py | ||
| test_gemini_savings_profile.py | ||
| test_header_safe_transforms.py | ||
| test_mcp_stats_aggregation.py | ||
| test_openai_backend_path.py | ||
| test_openai_chat_savings_profile.py | ||
| test_openai_responses_ccr.py | ||
| test_openai_stream_usage_option.py | ||
| test_openai_transport_path_prefix.py | ||
| test_openai_upstream_header.py | ||
| test_phase3_byte_identity.py | ||
| test_request_logger.py | ||
| test_transformations_feed.py | ||