Skip to content

fix(wrap): preserve pre-set ANTHROPIC_BASE_URL as proxy upstream#1358

Open
ousamabenyounes wants to merge 2 commits into
headroomlabs-ai:mainfrom
ousamabenyounes:fix/issue-1353
Open

fix(wrap): preserve pre-set ANTHROPIC_BASE_URL as proxy upstream#1358
ousamabenyounes wants to merge 2 commits into
headroomlabs-ai:mainfrom
ousamabenyounes:fix/issue-1353

Conversation

@ousamabenyounes

@ousamabenyounes ousamabenyounes commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Description

Issue #1353: when the user already has ANTHROPIC_BASE_URL pointing at a LiteLLM (or any custom Anthropic-compatible) gateway, headroom wrap claude overwrote it with the local proxy URL and silently forwarded to api.anthropic.com. wrap claude now treats a pre-existing non-self-pointing ANTHROPIC_BASE_URL as the proxy's upstream (passed as ANTHROPIC_TARGET_API_URL) so compression layers on top of the user's gateway instead of replacing it. Explicit ANTHROPIC_TARGET_API_URL, Foundry and Vertex paths still win.

Closes #1353

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

  • Add _detect_inbound_anthropic_upstream(proxy_port) to headroom/cli/wrap.py: returns a pre-set ANTHROPIC_BASE_URL as the proxy upstream, ignoring unset/blank values and self-pointing localhost URLs on the proxy port.
  • Wire it into wrap claude so a user's custom gateway is preserved as ANTHROPIC_TARGET_API_URL instead of being overwritten.
  • Precedence unchanged: explicit ANTHROPIC_TARGET_API_URL, Foundry, and Vertex still take priority.
  • Add tests/test_cli/test_wrap_claude_inbound_upstream.py (8 cases) covering detection, blank/unset, self-pointing URLs, and a different-port upstream.

Testing

  • Unit tests pass (pytest)
  • Linting passes (ruff check .)
  • Type checking passes (mypy headroom)
  • New tests added for new functionality
  • Manual testing performed

Test Output

tests/test_cli/test_wrap_claude_inbound_upstream.py::test_detects_custom_litellm_upstream PASSED
tests/test_cli/test_wrap_claude_inbound_upstream.py::test_returns_none_when_unset PASSED
tests/test_cli/test_wrap_claude_inbound_upstream.py::test_returns_none_when_blank PASSED
tests/test_cli/test_wrap_claude_inbound_upstream.py::test_returns_none_for_self_pointing_url[http://127.0.0.1:8787] PASSED
tests/test_cli/test_wrap_claude_inbound_upstream.py::test_returns_none_for_self_pointing_url[http://localhost:8787] PASSED
tests/test_cli/test_wrap_claude_inbound_upstream.py::test_returns_none_for_self_pointing_url[http://127.0.0.1:8787/] PASSED
tests/test_cli/test_wrap_claude_inbound_upstream.py::test_returns_none_for_self_pointing_url[http://LOCALHOST:8787/v1] PASSED
tests/test_cli/test_wrap_claude_inbound_upstream.py::test_returns_localhost_on_different_port PASSED

============================== 8 passed in 0.25s ===============================

Real Behavior Proof

  • Environment: Python 3.13, local checkout, pytest 9.0.3
  • Exact command / steps: pytest tests/test_cli/test_wrap_claude_inbound_upstream.py -v on the patched branch, then with the production fix reverted.
  • Observed result (RED → GREEN):
    • RED — with the fix reverted, all 8 tests fail: AttributeError: module 'headroom.cli.wrap' has no attribute '_detect_inbound_anthropic_upstream' (8 failed in 0.37s).
    • GREEN — with the fix applied, all 8 pass (8 passed in 0.25s).
  • Not tested: end-to-end live LiteLLM gateway round-trip (covered indirectly by the upstream-URL detection unit tests).

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

Additional Notes

Docs/CHANGELOG checklist items left unchecked as N/A: this is a behavioral bug fix to existing wrap claude upstream handling with no new public surface to document.

Real Behavior Proof

  • Environment: headroom 0.28.0 dev checkout (branch fix/issue-1353), .venv, proxy port 8787.
  • Exact command / steps: invoked the real detection path used by wrap claude (_detect_inbound_anthropic_upstream) across representative ANTHROPIC_BASE_URL values:
    python -c "from headroom.cli.wrap import _detect_inbound_anthropic_upstream as d; ..."
    
  • Observed result:
    custom LiteLLM gateway        -> 'https://litellm.mycorp.internal/v1'
    unset                         -> None
    blank                         -> None
    self-pointing localhost:8787  -> None
    self-pointing LOCALHOST/v1    -> None
    different port (real upstream)-> 'http://10.0.0.5:4000'
    
    A pre-set, non-self-pointing ANTHROPIC_BASE_URL is returned as the proxy upstream (wired to ANTHROPIC_TARGET_API_URL), so compression layers on top of the user's gateway. Unset / blank / self-pointing values fall through to None, so the proxy default applies and no self-forwarding loop is created.
  • Not tested: full wrap claude launch end-to-end against a live LiteLLM gateway (needs the external gateway + Claude Code); the wiring from custom_upstream to ANTHROPIC_TARGET_API_URL is covered by the unit suite.

@github-actions

github-actions Bot commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

PR governance

This PR does not yet satisfy the required template fields:

  • Fill in Real Behavior ProofObserved result.

Please update the PR body, or move the PR back to draft while it is still in progress.

@github-actions github-actions Bot added the status: needs author action Pull request body or readiness checklist still needs author updates label Jun 24, 2026
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

@JerrettDavis JerrettDavis left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed the wrap claude inbound upstream handling and ran uv run --with pytest python -m pytest tests/test_cli/test_wrap_claude_inbound_upstream.py -q: 8 passed. The precedence with explicit target/Foundry/Vertex is preserved, and self-pointing proxy URLs are ignored to avoid loops. No blocking issues found.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

status: needs author action Pull request body or readiness checklist still needs author updates

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Use with Litellm

2 participants