feat: add --disable-kompress-fallback to restore legacy PASSTHROUGH fallback (#1185)

## Description

Follow-up to #1046. That PR stopped `--disable-kompress` from forcing
`fallback_strategy = CompressionStrategy.PASSTHROUGH`, so
ContentRouter's rule-based
passes keep running when the ML model is off. As noted in review, that
is a behaviour
change for callers who relied on the old passthrough-everything
fallback.

This adds an opt-in `--disable-kompress-fallback` flag (env
`HEADROOM_DISABLE_KOMPRESS_FALLBACK`) that, together with
`--disable-kompress`, restores
the previous behaviour by routing fall-through content to `PASSTHROUGH`.
It defaults to
off, so the corrected behaviour from #1046 is unchanged unless a caller
explicitly opts
back in. The flag is a no-op unless `--disable-kompress` is also set.

## 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/proxy/models.py`: added `disable_kompress_fallback: bool =
False` to `ProxyConfig`.
- `headroom/proxy/server.py`: when `disable_kompress` and
`disable_kompress_fallback` are both set, restore
`router_config.fallback_strategy = CompressionStrategy.PASSTHROUGH`
(re-adding the `CompressionStrategy` import); wired the new field
through the env factory, the `__main__` argparse path
(`--disable-kompress-fallback`), and the `/health` config payload.
- `headroom/cli/proxy.py`: added the `--disable-kompress-fallback` Click
option (with `HEADROOM_DISABLE_KOMPRESS_FALLBACK` envvar) and passed it
into `ProxyConfig`.
- `tests/test_proxy_disable_kompress.py`: added tests for the flag
restoring `PASSTHROUGH`, for it being a no-op without
`--disable-kompress`, and for the `/health` config payload exposing the
field.
- `tests/test_cli_proxy_env.py`: added a test that the env factory
honours `HEADROOM_DISABLE_KOMPRESS_FALLBACK`.

## 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_disable_kompress.py -v
collected 5 items

tests/test_proxy_disable_kompress.py::test_disable_kompress_config_keeps_optimization_but_disables_ml_fallback PASSED [ 20%]
tests/test_proxy_disable_kompress.py::test_disable_kompress_defaults_to_existing_kompress_behavior PASSED [ 40%]
tests/test_proxy_disable_kompress.py::test_health_config_reports_disable_kompress_fallback PASSED [ 60%]
tests/test_proxy_disable_kompress.py::test_disable_kompress_fallback_restores_passthrough PASSED [ 80%]
tests/test_proxy_disable_kompress.py::test_disable_kompress_fallback_without_disable_kompress_is_noop PASSED [100%]

5 passed

$ ruff check headroom/proxy/server.py headroom/proxy/models.py headroom/cli/proxy.py tests/
All checks passed!
```

## Real Behavior Proof

- Environment: local clone, Python 3.13.7 venv, headroom core deps +
fastapi/uvicorn/httpx[http2].
- Exact command / steps: booted the app in-process with FastAPI
`TestClient` across four flag combinations and inspected both the live
`ContentRouter` config and the `/health` config payload.
- Observed result: both flags -> enable_kompress=False and
fallback_strategy=PASSTHROUGH (/health reports
disable_kompress_fallback=true); --disable-kompress alone ->
fallback_strategy stays KOMPRESS (the #1046 default, /health reports
false); --disable-kompress-fallback alone -> no-op
(enable_kompress=True, KOMPRESS); neither flag -> defaults
(enable_kompress=True, KOMPRESS).
- Not tested: full live-proxy `/stats` run against a real LLM backend.

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

The flag is intentionally a no-op unless `--disable-kompress` is also
set, mirroring where
the original override lived. Happy to add a short note to the
docs/README flag list if you'd
like it documented there.

Co-authored-by: JerrettDavis <mxjerrett@gmail.com>
This commit is contained in:
AKT99! 2026-06-23 09:21:55 +05:30 committed by GitHub
parent 359004646b
commit f309244a77
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 103 additions and 0 deletions

View file

@ -426,6 +426,16 @@ def dashboard(port: int, no_open: bool) -> None:
"Env: HEADROOM_DISABLE_KOMPRESS=1."
),
)
@click.option(
"--disable-kompress-fallback",
is_flag=True,
envvar="HEADROOM_DISABLE_KOMPRESS_FALLBACK",
help=(
"With --disable-kompress, route fall-through content to PASSTHROUGH instead of "
"the default KOMPRESS fallback (restores legacy --disable-kompress behaviour). "
"Env: HEADROOM_DISABLE_KOMPRESS_FALLBACK=1."
),
)
@click.option(
"--disable-kompress-anthropic/--enable-kompress-anthropic",
"disable_kompress_anthropic",
@ -731,6 +741,7 @@ def proxy(
budget_period: str,
code_aware_flag: bool | None,
disable_kompress: bool,
disable_kompress_fallback: bool,
disable_kompress_anthropic: bool | None,
disable_kompress_openai: bool | None,
code_graph: bool,
@ -959,6 +970,7 @@ def proxy(
in ("true", "1", "yes", "on")
),
disable_kompress=disable_kompress,
disable_kompress_fallback=disable_kompress_fallback,
disable_kompress_anthropic=disable_kompress_anthropic,
disable_kompress_openai=disable_kompress_openai,
# Code graph: live file watcher for incremental reindexing

View file

@ -154,6 +154,13 @@ class ProxyConfig:
# CLI: --disable-kompress; env: HEADROOM_DISABLE_KOMPRESS=1.
disable_kompress: bool = False
# With disable_kompress, route fall-through content to PASSTHROUGH instead
# of the default KOMPRESS fallback strategy. Restores the legacy
# --disable-kompress behaviour for callers that relied on it. No effect
# unless disable_kompress is also set.
# CLI: --disable-kompress-fallback; env: HEADROOM_DISABLE_KOMPRESS_FALLBACK=1.
disable_kompress_fallback: bool = False
# Per-provider overrides for `disable_kompress`. None inherits the global
# value above; True/False force-disable/enable Kompress for that provider's
# pipeline only (other compressors and all routing/exclusion are unaffected).

View file

@ -169,6 +169,7 @@ from headroom.transforms import (
CacheAligner,
CodeAwareCompressor,
CodeCompressorConfig,
CompressionStrategy,
ContentRouter,
ContentRouterConfig,
TransformPipeline,
@ -626,6 +627,10 @@ class HeadroomProxy(
)
if config.disable_kompress:
router_config.enable_kompress = False
# Opt-in restore of the legacy behaviour: send fall-through content
# to PASSTHROUGH instead of the default KOMPRESS fallback strategy.
if config.disable_kompress_fallback:
router_config.fallback_strategy = CompressionStrategy.PASSTHROUGH
# A non-None exclude_tools replaces DEFAULT_EXCLUDE_TOOLS in
# ContentRouter, so merge rather than assign.
if config.exclude_tools:
@ -2068,6 +2073,7 @@ def create_app(config: ProxyConfig | None = None) -> FastAPI:
"cache": config.cache_enabled,
"rate_limit": config.rate_limit_enabled,
"disable_kompress": config.disable_kompress,
"disable_kompress_fallback": config.disable_kompress_fallback,
"disable_kompress_anthropic": config.disable_kompress_anthropic,
"disable_kompress_openai": config.disable_kompress_openai,
"memory": config.memory_enabled,
@ -3770,6 +3776,7 @@ def _proxy_config_from_env() -> ProxyConfig:
bedrock_api_url=os.environ.get("BEDROCK_TARGET_API_URL"),
anyllm_provider=_get_env_str("HEADROOM_ANYLLM_PROVIDER", "openai"),
disable_kompress=_get_env_bool("HEADROOM_DISABLE_KOMPRESS", False),
disable_kompress_fallback=_get_env_bool("HEADROOM_DISABLE_KOMPRESS_FALLBACK", False),
disable_kompress_anthropic=_get_env_optional_bool("HEADROOM_DISABLE_KOMPRESS_ANTHROPIC"),
disable_kompress_openai=_get_env_optional_bool("HEADROOM_DISABLE_KOMPRESS_OPENAI"),
max_connections=_get_env_int("HEADROOM_MAX_CONNECTIONS", 500),
@ -4165,6 +4172,15 @@ if __name__ == "__main__":
"Also settable via HEADROOM_DISABLE_KOMPRESS=1."
),
)
parser.add_argument(
"--disable-kompress-fallback",
action="store_true",
help=(
"With --disable-kompress, route fall-through content to PASSTHROUGH instead of "
"the default KOMPRESS fallback (restores legacy --disable-kompress behaviour). "
"Also settable via HEADROOM_DISABLE_KOMPRESS_FALLBACK=1."
),
)
parser.add_argument(
"--disable-kompress-anthropic",
dest="disable_kompress_anthropic",
@ -4259,6 +4275,9 @@ if __name__ == "__main__":
cache_enabled = env_cache if not args.no_cache else False
rate_limit_enabled = env_rate_limit if not args.no_rate_limit else False
disable_kompress = args.disable_kompress or _get_env_bool("HEADROOM_DISABLE_KOMPRESS", False)
disable_kompress_fallback = args.disable_kompress_fallback or _get_env_bool(
"HEADROOM_DISABLE_KOMPRESS_FALLBACK", False
)
disable_kompress_anthropic = (
args.disable_kompress_anthropic
if args.disable_kompress_anthropic is not None
@ -4312,6 +4331,7 @@ if __name__ == "__main__":
log_full_messages=args.log_messages or _get_env_bool("HEADROOM_LOG_MESSAGES", False),
code_aware_enabled=code_aware_enabled,
disable_kompress=disable_kompress,
disable_kompress_fallback=disable_kompress_fallback,
disable_kompress_anthropic=disable_kompress_anthropic,
disable_kompress_openai=disable_kompress_openai,
# Connection pool settings

View file

@ -927,6 +927,15 @@ class TestArgparseBackendValidation:
assert config.disable_kompress is True
def test_proxy_config_from_env_reads_disable_kompress_fallback(self):
"""The direct server env path should honor HEADROOM_DISABLE_KOMPRESS_FALLBACK."""
from headroom.proxy.server import _proxy_config_from_env
with patch.dict(os.environ, {"HEADROOM_DISABLE_KOMPRESS_FALLBACK": "1"}):
config = _proxy_config_from_env()
assert config.disable_kompress_fallback is True
def test_argparse_registers_keepalive_expiry_flag(self):
"""The argparse path (python -m headroom.proxy.server) must register
--keepalive-expiry as a float flag, so it can override the

View file

@ -49,3 +49,58 @@ def test_disable_kompress_defaults_to_existing_kompress_behavior() -> None:
assert router.config.enable_kompress is True
assert router.config.fallback_strategy == CompressionStrategy.KOMPRESS
def test_health_config_reports_disable_kompress_fallback(monkeypatch: pytest.MonkeyPatch) -> None:
from fastapi.testclient import TestClient
monkeypatch.setenv("HEADROOM_SKIP_UPSTREAM_CHECK", "1")
app = create_app(
ProxyConfig(
optimize=True,
disable_kompress=True,
disable_kompress_fallback=True,
cache_enabled=False,
rate_limit_enabled=False,
cost_tracking_enabled=False,
log_requests=False,
)
)
with TestClient(app, base_url="http://127.0.0.1", client=("127.0.0.1", 12345)) as client:
config = client.get("/health").json()["config"]
assert config["disable_kompress"] is True
assert config["disable_kompress_fallback"] is True
def test_disable_kompress_fallback_restores_passthrough() -> None:
router = _proxy_router(
ProxyConfig(
optimize=True,
disable_kompress=True,
disable_kompress_fallback=True,
cache_enabled=False,
rate_limit_enabled=False,
cost_tracking_enabled=False,
log_requests=False,
)
)
assert router.config.enable_kompress is False
assert router.config.fallback_strategy == CompressionStrategy.PASSTHROUGH
def test_disable_kompress_fallback_without_disable_kompress_is_noop() -> None:
router = _proxy_router(
ProxyConfig(
optimize=True,
disable_kompress_fallback=True,
cache_enabled=False,
rate_limit_enabled=False,
cost_tracking_enabled=False,
log_requests=False,
)
)
assert router.config.enable_kompress is True
assert router.config.fallback_strategy == CompressionStrategy.KOMPRESS