mirror of
https://github.com/headroomlabs-ai/headroom.git
synced 2026-08-27 14:17:10 -04:00
## Description `headroom wrap claude` is the recommended Claude Code integration, but for subscription users entitled to the **1M** context window it silently caps usable context at **200k**. Root cause (upstream, anthropics/claude-code#68522): when `ANTHROPIC_BASE_URL` points at a custom host (the Headroom proxy), Claude Code does **not** send the `context-1m-2025-08-07` beta header and treats the window as 200k. The `/model opus[1m]` picker selection does not survive a custom base URL, and `CLAUDE_CODE_AUTO_COMPACT_WINDOW` alone does not lift the cap. Headroom itself already forwards `anthropic-beta` and sizes Opus at 1M internally — but since `wrap claude` owns the launched process's environment and is the documented path, users hit this and blame Headroom first. This adds the opt-in fix the issue proposes. Closes #1158 ## 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/cli/wrap.py`: new opt-in `--1m` flag on `wrap claude`. When set, `ANTHROPIC_MODEL=<opus>[1m]` is exported on the launched process so Claude Code sends the `context-1m` beta header. Logic extracted to a testable helper `_resolve_1m_model`: a model the user already selected via `ANTHROPIC_MODEL` is preserved (only the `[1m]` suffix is appended when missing); otherwise it falls back to the default Opus. Idempotent (no double suffix). Default behavior is unchanged (opt-in). - `tests/test_cli/test_wrap_helpers.py`: unit tests for `_resolve_1m_model` (append-to-user-model, idempotent, default fallback). - `README.md`: `--1m` added to the Claude Code row of the agent compatibility matrix. - `CHANGELOG.md`: Unreleased → Features entry. ## Testing - [x] Unit tests pass (`pytest`) - [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 tests/test_cli/test_wrap_helpers.py tests/test_cli/test_wrap_claude_base_url.py -q 61 passed in 0.46s $ uv run ruff check headroom/cli/wrap.py tests/test_cli/test_wrap_helpers.py All checks passed! $ uv run mypy headroom/cli/wrap.py Success: no issues found in 1 source file ``` #### TDD verification (RED → GREEN) RED — new tests with the prod change reverted (`_resolve_1m_model` absent): ```text E AttributeError: module 'headroom.cli.wrap' has no attribute '_resolve_1m_model' 3 failed, 40 deselected in 0.56s ``` GREEN — with the change applied: ```text 3 passed, 40 deselected in 0.34s ``` ## Real Behavior Proof - Environment: Linux, Python 3.13, headroom @ this branch. - Exact command / steps: `headroom wrap claude --1m --help` shows the new flag, and the flag resolves the model id that triggers the 1M window: ```text $ headroom wrap claude --help | grep -A1 -- --1m --1m Preserve the 1M context window. Behind a custom ANTHROPIC_BASE_URL Claude Code drops the ... # model-id resolution (what --1m exports as ANTHROPIC_MODEL): _resolve_1m_model("claude-opus-4-1-20250805") -> "claude-opus-4-1-20250805[1m]" _resolve_1m_model("claude-opus-4-8[1m]") -> "claude-opus-4-8[1m]" (idempotent) _resolve_1m_model(None) -> "claude-opus-4-8[1m]" (default) ``` - Observed result: with `--1m`, the launched Claude Code process gets `ANTHROPIC_MODEL=<opus>[1m]`, which is the documented trigger for the `context-1m` beta header (verified in the issue against `~/.headroom/logs/proxy.log`). - Not tested: the live Claude Code subscription handshake against Anthropic's servers (requires a 1M-entitled subscription + the proprietary client); the model-id → header behavior is Claude Code's, documented in the issue and upstream anthropics/claude-code#68522. Headroom's side (export the env var that flips it on) is covered above and by the unit 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'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 have updated the CHANGELOG.md if applicable ## Additional Notes Opt-in only — without `--1m` nothing changes. The `_DEFAULT_1M_MODEL` constant is only consulted when the user has no `ANTHROPIC_MODEL` set; users on a specific model keep it (suffix appended), so the default's freshness does not affect them. --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|---|---|---|
| .. | ||
| test_copilot_auth.py | ||
| test_init_cli.py | ||
| test_init_enable_tool_search.py | ||
| test_install_cli.py | ||
| test_main_help_version.py | ||
| test_mcp.py | ||
| test_serena_disable.py | ||
| test_serena_migrate.py | ||
| test_subprocess_utf8_encoding.py | ||
| test_unwrap_claude.py | ||
| test_wrap_aider.py | ||
| test_wrap_bridge.py | ||
| test_wrap_claude_base_url.py | ||
| test_wrap_codex.py | ||
| test_wrap_continue.py | ||
| test_wrap_copilot.py | ||
| test_wrap_goose.py | ||
| test_wrap_helpers.py | ||
| test_wrap_hintfile_agents.py | ||
| test_wrap_openclaw.py | ||
| test_wrap_opencode.py | ||
| test_wrap_openhands.py | ||
| test_wrap_persistent.py | ||
| test_wrap_rtk_metrics.py | ||
| test_wrap_vibe.py | ||