"""Tests for CLI proxy env variable handling and backend validation. Verifies that: 1. Provider target URL env vars are read by `headroom proxy` 2. litellm-* backends are accepted by both CLI and argparse paths 3. HEADROOM_WRAP_PROXY_TIMEOUT controls `headroom wrap` proxy readiness waits """ import os from unittest.mock import patch import pytest click = pytest.importorskip("click") pytest.importorskip("fastapi") from click.testing import CliRunner # noqa: E402 from headroom.cli import wrap as wrap_mod # noqa: E402 from headroom.cli.main import main # noqa: E402 @pytest.fixture def runner(): return CliRunner() class _FakeProxyProcess: returncode = None def __init__(self): self.killed = False def poll(self): return None def kill(self): self.killed = True class TestCLIWrapProxyTimeout: """Test wrap proxy readiness timeout configuration.""" def test_default_timeout_stays_current_without_ml_extras(self, monkeypatch): monkeypatch.delenv(wrap_mod._WRAP_PROXY_TIMEOUT_ENV, raising=False) monkeypatch.setattr(wrap_mod, "_ml_wrap_extras_detected", lambda: False) assert ( wrap_mod._resolve_wrap_proxy_timeout_seconds() == wrap_mod._WRAP_PROXY_TIMEOUT_DEFAULT_SECONDS ) def test_default_timeout_is_longer_when_ml_extras_detected(self, monkeypatch): monkeypatch.delenv(wrap_mod._WRAP_PROXY_TIMEOUT_ENV, raising=False) monkeypatch.setattr(wrap_mod, "_ml_wrap_extras_detected", lambda: True) assert ( wrap_mod._resolve_wrap_proxy_timeout_seconds() == wrap_mod._WRAP_PROXY_TIMEOUT_ML_DEFAULT_SECONDS ) def test_start_proxy_succeeds_when_ready_within_default_timeout(self, monkeypatch, tmp_path): fake_proc = _FakeProxyProcess() sleeps = [] monkeypatch.delenv(wrap_mod._WRAP_PROXY_TIMEOUT_ENV, raising=False) monkeypatch.setattr(wrap_mod, "_ml_wrap_extras_detected", lambda: False) monkeypatch.setattr(wrap_mod, "_get_log_path", lambda: tmp_path / "proxy.log") monkeypatch.setattr(wrap_mod, "_check_proxy", lambda _port: True) monkeypatch.setattr(wrap_mod.time, "sleep", lambda seconds: sleeps.append(seconds)) monkeypatch.setattr(wrap_mod.subprocess, "Popen", lambda *args, **kwargs: fake_proc) proc = wrap_mod._start_proxy(8787, agent_type="codex") assert proc is fake_proc assert sleeps == [1] assert fake_proc.killed is False def test_start_proxy_passes_resolved_copilot_api_url_to_proxy(self, monkeypatch, tmp_path): fake_proc = _FakeProxyProcess() captured: dict[str, object] = {} monkeypatch.delenv(wrap_mod._WRAP_PROXY_TIMEOUT_ENV, raising=False) monkeypatch.setattr(wrap_mod, "_ml_wrap_extras_detected", lambda: False) monkeypatch.setattr(wrap_mod, "_get_log_path", lambda: tmp_path / "proxy.log") monkeypatch.setattr(wrap_mod, "_check_proxy", lambda _port: True) monkeypatch.setattr(wrap_mod.time, "sleep", lambda _seconds: None) def fake_popen(*args, **kwargs): # noqa: ANN002, ANN003 captured["args"] = args captured["kwargs"] = kwargs return fake_proc monkeypatch.setattr(wrap_mod.subprocess, "Popen", fake_popen) proc = wrap_mod._start_proxy( 8787, agent_type="copilot", openai_api_url="https://copilot-api.acme.ghe.com", copilot_api_token="copilot-api-token", ) assert proc is fake_proc env = captured["kwargs"]["env"] assert env["OPENAI_TARGET_API_URL"] == "https://copilot-api.acme.ghe.com" assert env["GITHUB_COPILOT_API_URL"] == "https://copilot-api.acme.ghe.com" assert env["GITHUB_COPILOT_API_TOKEN"] == "copilot-api-token" def test_start_proxy_redirects_subprocess_stdio_to_standalone_log(self, monkeypatch, tmp_path): fake_proc = _FakeProxyProcess() captured: dict[str, object] = {} logs: list[str] = [] monkeypatch.delenv(wrap_mod._WRAP_PROXY_TIMEOUT_ENV, raising=False) monkeypatch.setattr(wrap_mod, "_get_log_path", lambda: tmp_path / "proxy.log") monkeypatch.setattr(wrap_mod, "_check_proxy", lambda _port: True) monkeypatch.setattr(wrap_mod.time, "sleep", lambda _seconds: None) monkeypatch.setattr(wrap_mod, "_ml_wrap_extras_detected", lambda: False) monkeypatch.setattr(wrap_mod.click, "echo", lambda message: logs.append(str(message))) def fake_popen(*args, **kwargs): # noqa: ANN002, ANN003 captured["kwargs"] = kwargs return fake_proc monkeypatch.setattr(wrap_mod.subprocess, "Popen", fake_popen) proc = wrap_mod._start_proxy(8787, agent_type="codex") assert proc is fake_proc assert captured["kwargs"]["stdout"] is captured["kwargs"]["stderr"] assert captured["kwargs"]["stdout"].name == str(tmp_path / "proxy-stdio.log") assert captured["kwargs"]["stdout"].name != str(tmp_path / "proxy.log") assert f" Logs: {tmp_path / 'proxy.log'}" in logs def test_env_timeout_allows_slow_start_proxy_to_succeed(self, monkeypatch, tmp_path): fake_proc = _FakeProxyProcess() sleeps = [] checks = [] monkeypatch.setenv(wrap_mod._WRAP_PROXY_TIMEOUT_ENV, "4") monkeypatch.setattr(wrap_mod, "_get_log_path", lambda: tmp_path / "proxy.log") monkeypatch.setattr(wrap_mod.time, "sleep", lambda seconds: sleeps.append(seconds)) monkeypatch.setattr(wrap_mod.subprocess, "Popen", lambda *args, **kwargs: fake_proc) def ready_on_fourth_check(port): checks.append(port) return len(checks) == 4 monkeypatch.setattr(wrap_mod, "_check_proxy", ready_on_fourth_check) proc = wrap_mod._start_proxy(8787, agent_type="codex") assert proc is fake_proc assert checks == [8787, 8787, 8787, 8787] assert sleeps == [1, 1, 1, 1] assert fake_proc.killed is False def test_start_proxy_tail_reads_standalone_stdio_log_on_process_exit( self, monkeypatch, tmp_path ): fake_proc = _FakeProxyProcess() fake_proc.returncode = 1 fake_proc.poll = lambda: fake_proc.returncode monkeypatch.setenv(wrap_mod._WRAP_PROXY_TIMEOUT_ENV, "2") monkeypatch.setattr(wrap_mod, "_get_log_path", lambda: tmp_path / "proxy.log") monkeypatch.setattr(wrap_mod, "_check_proxy", lambda _port: False) monkeypatch.setattr(wrap_mod.time, "sleep", lambda _seconds: None) monkeypatch.setattr(wrap_mod.subprocess, "Popen", lambda *args, **kwargs: fake_proc) (tmp_path / "proxy.log").write_text("canonical runtime log output") (tmp_path / "proxy-stdio.log").write_text("proxy stdio startup output") with pytest.raises(RuntimeError) as excinfo: wrap_mod._start_proxy(8787, agent_type="codex") message = str(excinfo.value) assert "Proxy exited with code 1" in message assert "proxy stdio startup output" in message assert "canonical runtime log output" not in message def test_timeout_error_names_configured_timeout_and_env_var(self, monkeypatch, tmp_path): fake_proc = _FakeProxyProcess() monkeypatch.setenv(wrap_mod._WRAP_PROXY_TIMEOUT_ENV, "2") monkeypatch.setattr(wrap_mod, "_get_log_path", lambda: tmp_path / "proxy.log") monkeypatch.setattr(wrap_mod, "_check_proxy", lambda _port: False) monkeypatch.setattr(wrap_mod.time, "sleep", lambda _seconds: None) monkeypatch.setattr(wrap_mod.subprocess, "Popen", lambda *args, **kwargs: fake_proc) with pytest.raises(RuntimeError) as excinfo: wrap_mod._start_proxy(8787, agent_type="codex") message = str(excinfo.value) assert "within 2 seconds" in message assert wrap_mod._WRAP_PROXY_TIMEOUT_ENV in message assert fake_proc.killed is True class TestCLIProxyEnvVars: """Test that the CLI proxy command reads API URL env vars.""" def test_headroom_host_from_env(self, runner): """HEADROOM_HOST env var should be passed to ProxyConfig.""" captured_config = {} def mock_run_server(config, **kwargs): captured_config["config"] = config with patch("headroom.proxy.server.run_server", mock_run_server): result = runner.invoke( main, ["proxy"], env={"HEADROOM_HOST": "0.0.0.0"}, catch_exceptions=False, ) assert result.exit_code == 0, result.output assert captured_config["config"].host == "0.0.0.0" def test_headroom_port_from_env(self, runner): """HEADROOM_PORT env var should be passed to ProxyConfig.""" captured_config = {} def mock_run_server(config, **kwargs): captured_config["config"] = config with patch("headroom.proxy.server.run_server", mock_run_server): result = runner.invoke( main, ["proxy"], env={"HEADROOM_PORT": "9797"}, catch_exceptions=False, ) assert result.exit_code == 0, result.output assert captured_config["config"].port == 9797 def test_headroom_min_tokens_from_env(self, runner): """HEADROOM_MIN_TOKENS env var should be passed to ProxyConfig.""" captured_config = {} def mock_run_server(config, **kwargs): captured_config["config"] = config with patch("headroom.proxy.server.run_server", mock_run_server): result = runner.invoke( main, ["proxy"], env={"HEADROOM_MIN_TOKENS": "120"}, catch_exceptions=False, ) assert result.exit_code == 0, result.output assert captured_config["config"].min_tokens_to_crush == 120 def test_headroom_min_tokens_zero_is_preserved(self, runner): """HEADROOM_MIN_TOKENS=0 is a legitimate value ("crush everything") and must not be discarded by an `or 500` fallback (regression).""" captured_config = {} def mock_run_server(config, **kwargs): captured_config["config"] = config with patch("headroom.proxy.server.run_server", mock_run_server): result = runner.invoke( main, ["proxy"], env={"HEADROOM_MIN_TOKENS": "0", "HEADROOM_MAX_ITEMS": "0"}, catch_exceptions=False, ) assert result.exit_code == 0, result.output assert captured_config["config"].min_tokens_to_crush == 0 assert captured_config["config"].max_items_after_crush == 0 def test_headroom_budget_from_env(self, runner): """HEADROOM_BUDGET env var should be passed to ProxyConfig.""" captured_config = {} def mock_run_server(config, **kwargs): captured_config["config"] = config with patch("headroom.proxy.server.run_server", mock_run_server): result = runner.invoke( main, ["proxy"], env={"HEADROOM_BUDGET": "100.5"}, catch_exceptions=False, ) assert result.exit_code == 0, result.output assert captured_config["config"].budget_limit_usd == 100.5 def test_budget_period_flag_and_env(self, runner): """--budget-period and HEADROOM_BUDGET_PERIOD should reach ProxyConfig.""" captured_config = {} def mock_run_server(config, **kwargs): captured_config["config"] = config with patch("headroom.proxy.server.run_server", mock_run_server): result = runner.invoke( main, ["proxy", "--budget", "50", "--budget-period", "monthly"], catch_exceptions=False, ) assert result.exit_code == 0, result.output assert captured_config["config"].budget_period == "monthly" with patch("headroom.proxy.server.run_server", mock_run_server): result = runner.invoke( main, ["proxy"], env={"HEADROOM_BUDGET_PERIOD": "hourly"}, catch_exceptions=False, ) assert result.exit_code == 0, result.output assert captured_config["config"].budget_period == "hourly" def test_code_aware_enabled_from_env(self, runner): """HEADROOM_CODE_AWARE_ENABLED env var should be passed to ProxyConfig.""" captured_config = {} def mock_run_server(config, **kwargs): captured_config["config"] = config with patch("headroom.proxy.server.run_server", mock_run_server): result = runner.invoke( main, ["proxy"], env={"HEADROOM_CODE_AWARE_ENABLED": "true"}, catch_exceptions=False, ) assert result.exit_code == 0, result.output assert captured_config["config"].code_aware_enabled is True def test_code_aware_enabled_defaults_true(self, runner): """Without HEADROOM_CODE_AWARE_ENABLED, code-aware defaults ON (coding posture; consistent with the argparse server path). It degrades to a no-op when tree-sitter isn't installed, so defaulting it on is safe.""" captured_config = {} def mock_run_server(config, **kwargs): captured_config["config"] = config env = {k: v for k, v in os.environ.items() if k != "HEADROOM_CODE_AWARE_ENABLED"} with ( patch("headroom.proxy.server.run_server", mock_run_server), patch.dict(os.environ, env, clear=True), ): result = runner.invoke( main, ["proxy"], catch_exceptions=False, ) assert result.exit_code == 0, result.output assert captured_config["config"].code_aware_enabled is True def test_code_aware_enabled_from_cli_flag(self, runner): """--code-aware should enable code-aware compression in the wrapper.""" captured_config = {} def mock_run_server(config, **kwargs): captured_config["config"] = config with patch("headroom.proxy.server.run_server", mock_run_server): result = runner.invoke(main, ["proxy", "--code-aware"], catch_exceptions=False) assert result.exit_code == 0, result.output assert captured_config["config"].code_aware_enabled is True def test_disable_kompress_from_env(self, runner): """HEADROOM_DISABLE_KOMPRESS should be passed to ProxyConfig.""" captured_config = {} def mock_run_server(config, **kwargs): captured_config["config"] = config with patch("headroom.proxy.server.run_server", mock_run_server): result = runner.invoke( main, ["proxy"], env={"HEADROOM_DISABLE_KOMPRESS": "1"}, catch_exceptions=False, ) assert result.exit_code == 0, result.output assert captured_config["config"].disable_kompress is True def test_disable_kompress_from_cli_flag(self, runner): """--disable-kompress should disable Kompress ML compression.""" captured_config = {} def mock_run_server(config, **kwargs): captured_config["config"] = config with patch("headroom.proxy.server.run_server", mock_run_server): result = runner.invoke( main, ["proxy", "--disable-kompress"], catch_exceptions=False, ) assert result.exit_code == 0, result.output assert captured_config["config"].disable_kompress is True def test_code_aware_flag_overrides_env_var(self, runner): """--code-aware should win over HEADROOM_CODE_AWARE_ENABLED=false.""" captured_config = {} def mock_run_server(config, **kwargs): captured_config["config"] = config with patch("headroom.proxy.server.run_server", mock_run_server): result = runner.invoke( main, ["proxy", "--code-aware"], env={"HEADROOM_CODE_AWARE_ENABLED": "false"}, catch_exceptions=False, ) assert result.exit_code == 0, result.output assert captured_config["config"].code_aware_enabled is True def test_openai_target_api_url_from_env(self, runner): """OPENAI_TARGET_API_URL env var should be passed to ProxyConfig.""" captured_config = {} def mock_run_server(config, **kwargs): captured_config["config"] = config with patch("headroom.proxy.server.run_server", mock_run_server): result = runner.invoke( main, ["proxy"], env={"OPENAI_TARGET_API_URL": "http://my-vllm:4000"}, catch_exceptions=False, ) assert result.exit_code == 0, result.output assert captured_config["config"].openai_api_url == "http://my-vllm:4000" def test_gemini_target_api_url_from_env(self, runner): """GEMINI_TARGET_API_URL env var should be passed to ProxyConfig.""" captured_config = {} def mock_run_server(config, **kwargs): captured_config["config"] = config with patch("headroom.proxy.server.run_server", mock_run_server): result = runner.invoke( main, ["proxy"], env={"GEMINI_TARGET_API_URL": "http://my-gemini:5000"}, catch_exceptions=False, ) assert result.exit_code == 0, result.output assert captured_config["config"].gemini_api_url == "http://my-gemini:5000" def test_vertex_target_api_url_from_env(self, runner): """VERTEX_TARGET_API_URL env var should be passed to ProxyConfig.""" captured_config = {} def mock_run_server(config, **kwargs): captured_config["config"] = config with patch("headroom.proxy.server.run_server", mock_run_server): result = runner.invoke( main, ["proxy"], env={"VERTEX_TARGET_API_URL": "https://europe-west4-aiplatform.googleapis.com"}, catch_exceptions=False, ) assert result.exit_code == 0, result.output assert ( captured_config["config"].vertex_api_url == "https://europe-west4-aiplatform.googleapis.com" ) def test_openai_api_url_cli_flag(self, runner): """--openai-api-url CLI flag should take precedence.""" captured_config = {} def mock_run_server(config, **kwargs): captured_config["config"] = config with patch("headroom.proxy.server.run_server", mock_run_server): result = runner.invoke( main, ["proxy", "--openai-api-url", "http://from-cli:4000"], catch_exceptions=False, ) assert result.exit_code == 0, result.output assert captured_config["config"].openai_api_url == "http://from-cli:4000" def test_vertex_api_url_cli_flag(self, runner): """--vertex-api-url CLI flag should take precedence.""" captured_config = {} def mock_run_server(config, **kwargs): captured_config["config"] = config with patch("headroom.proxy.server.run_server", mock_run_server): result = runner.invoke( main, ["proxy", "--vertex-api-url", "https://us-east5-aiplatform.googleapis.com"], catch_exceptions=False, ) assert result.exit_code == 0, result.output assert ( captured_config["config"].vertex_api_url == "https://us-east5-aiplatform.googleapis.com" ) def test_cli_flag_overrides_env_var(self, runner): """CLI flag should take precedence over env var.""" captured_config = {} def mock_run_server(config, **kwargs): captured_config["config"] = config with patch("headroom.proxy.server.run_server", mock_run_server): result = runner.invoke( main, ["proxy", "--openai-api-url", "http://from-cli:4000"], env={"OPENAI_TARGET_API_URL": "http://from-env:4000"}, catch_exceptions=False, ) assert result.exit_code == 0, result.output assert captured_config["config"].openai_api_url == "http://from-cli:4000" def test_no_env_var_defaults_to_none(self, runner): """Without env var or flag, openai_api_url should be None.""" captured_config = {} def mock_run_server(config, **kwargs): captured_config["config"] = config # Ensure the env var is not set env = {k: v for k, v in os.environ.items() if k != "OPENAI_TARGET_API_URL"} with ( patch("headroom.proxy.server.run_server", mock_run_server), patch.dict(os.environ, env, clear=True), ): result = runner.invoke( main, ["proxy"], catch_exceptions=False, ) assert result.exit_code == 0, result.output assert captured_config["config"].openai_api_url is None def test_both_api_urls_from_env(self, runner): """Both OPENAI and GEMINI target URLs can be set via env.""" captured_config = {} def mock_run_server(config, **kwargs): captured_config["config"] = config with patch("headroom.proxy.server.run_server", mock_run_server): result = runner.invoke( main, ["proxy"], env={ "OPENAI_TARGET_API_URL": "http://my-vllm:4000", "GEMINI_TARGET_API_URL": "http://my-gemini:5000", }, catch_exceptions=False, ) assert result.exit_code == 0, result.output assert captured_config["config"].openai_api_url == "http://my-vllm:4000" assert captured_config["config"].gemini_api_url == "http://my-gemini:5000" @pytest.mark.parametrize("timeout", [-1, 0, 1, 10000]) def test_request_timeout_cli_flags(self, runner, timeout): """Fast-fail CLI flags should map into ProxyConfig.""" captured_config = {} def mock_run_server(config, **kwargs): captured_config["config"] = config with patch("headroom.proxy.server.run_server", mock_run_server): result = runner.invoke( main, ["proxy", "--request-timeout-seconds", f"{timeout}"], catch_exceptions=False, ) assert result.exit_code == 0, result.output assert ( captured_config["config"].request_timeout_seconds == timeout if timeout and timeout > 0 else 300 ) @pytest.mark.parametrize("timeout", [-1, 0, 1, 10000]) def test_request_timeout_from_env(self, runner, timeout): """HEADROOM_REQUEST_TIMEOUT env var should be passed to ProxyConfig.""" captured_config = {} def mock_run_server(config, **kwargs): captured_config["config"] = config with patch("headroom.proxy.server.run_server", mock_run_server): result = runner.invoke( main, ["proxy"], env={"HEADROOM_REQUEST_TIMEOUT": f"{timeout}"}, catch_exceptions=False, ) assert result.exit_code == 0, result.output assert ( captured_config["config"].request_timeout_seconds == timeout if timeout and timeout > 0 else 300 ) def test_retry_and_connect_timeout_cli_flags(self, runner): """Fast-fail CLI flags should map into ProxyConfig.""" captured_config = {} def mock_run_server(config, **kwargs): captured_config["config"] = config with patch("headroom.proxy.server.run_server", mock_run_server): result = runner.invoke( main, [ "proxy", "--retry-max-attempts", "1", "--connect-timeout-seconds", "3", ], catch_exceptions=False, ) assert result.exit_code == 0, result.output assert captured_config["config"].retry_max_attempts == 1 assert captured_config["config"].connect_timeout_seconds == 3 def test_production_scaling_env_vars(self, runner): captured = {} def mock_run_server(config, **kwargs): captured["config"] = config captured["kwargs"] = kwargs with patch("headroom.proxy.server.run_server", mock_run_server): result = runner.invoke( main, ["proxy"], env={ "HEADROOM_WORKERS": "4", "HEADROOM_LIMIT_CONCURRENCY": "250", "HEADROOM_MAX_CONNECTIONS": "200", "HEADROOM_MAX_KEEPALIVE": "50", }, catch_exceptions=False, ) assert result.exit_code == 0, result.output assert captured["config"].max_connections == 200 assert captured["config"].max_keepalive_connections == 50 # Click CLI also passes `print_banner=False` to suppress the legacy # run_server banner (cli/proxy.py prints its own). Assert the # production-scaling keys we care about, not the full kwargs dict. assert captured["kwargs"]["workers"] == 4 assert captured["kwargs"]["limit_concurrency"] == 250 assert captured["kwargs"].get("print_banner") is False def test_keepalive_expiry_env_var(self, runner): captured = {} def mock_run_server(config, **kwargs): captured["config"] = config captured["kwargs"] = kwargs with patch("headroom.proxy.server.run_server", mock_run_server): result = runner.invoke( main, ["proxy"], env={"HEADROOM_KEEPALIVE_EXPIRY": "45"}, catch_exceptions=False, ) assert result.exit_code == 0, result.output assert captured["config"].keepalive_expiry == 45.0 def test_production_scaling_cli_flags_override_env_vars(self, runner): captured = {} def mock_run_server(config, **kwargs): captured["config"] = config captured["kwargs"] = kwargs with patch("headroom.proxy.server.run_server", mock_run_server): result = runner.invoke( main, [ "proxy", "--workers", "3", "--limit-concurrency", "125", "--max-connections", "150", "--max-keepalive", "25", ], env={ "HEADROOM_WORKERS": "4", "HEADROOM_LIMIT_CONCURRENCY": "250", "HEADROOM_MAX_CONNECTIONS": "200", "HEADROOM_MAX_KEEPALIVE": "50", }, catch_exceptions=False, ) assert result.exit_code == 0, result.output assert captured["config"].max_connections == 150 assert captured["config"].max_keepalive_connections == 25 # Click CLI also passes `print_banner=False`. Assert production # scaling keys explicitly rather than the full kwargs dict. assert captured["kwargs"]["workers"] == 3 assert captured["kwargs"]["limit_concurrency"] == 125 assert captured["kwargs"].get("print_banner") is False class TestCLIProxyBackend: """Test that litellm-* backends are accepted by the CLI.""" def test_litellm_hosted_vllm_backend_accepted(self, runner): """--backend litellm-hosted_vllm should be accepted (not rejected).""" captured_config = {} def mock_run_server(config, **kwargs): captured_config["config"] = config with patch("headroom.proxy.server.run_server", mock_run_server): result = runner.invoke( main, ["proxy", "--backend", "litellm-hosted_vllm"], catch_exceptions=False, ) assert result.exit_code == 0, result.output assert captured_config["config"].backend == "litellm-hosted_vllm" def test_litellm_vertex_backend_accepted(self, runner): """--backend litellm-vertex should be accepted.""" captured_config = {} def mock_run_server(config, **kwargs): captured_config["config"] = config with patch("headroom.proxy.server.run_server", mock_run_server): result = runner.invoke( main, ["proxy", "--backend", "litellm-vertex"], catch_exceptions=False, ) assert result.exit_code == 0, result.output assert captured_config["config"].backend == "litellm-vertex" def test_litellm_backend_with_openai_url(self, runner): """Full vLLM setup: litellm backend + OPENAI_TARGET_API_URL.""" captured_config = {} def mock_run_server(config, **kwargs): captured_config["config"] = config with patch("headroom.proxy.server.run_server", mock_run_server): result = runner.invoke( main, [ "proxy", "--backend", "litellm-hosted_vllm", "--openai-api-url", "http://my-vllm:4000", ], catch_exceptions=False, ) assert result.exit_code == 0, result.output assert captured_config["config"].backend == "litellm-hosted_vllm" assert captured_config["config"].openai_api_url == "http://my-vllm:4000" class TestCLIAnyllmProviderEnv: """Test that HEADROOM_ANYLLM_PROVIDER env var is read by the CLI.""" def test_anyllm_provider_from_env(self, runner): """HEADROOM_ANYLLM_PROVIDER env var should override the default.""" captured_config = {} def mock_run_server(config, **kwargs): captured_config["config"] = config with patch("headroom.proxy.server.run_server", mock_run_server): result = runner.invoke( main, ["proxy", "--backend", "anyllm"], env={"HEADROOM_ANYLLM_PROVIDER": "llamacpp"}, catch_exceptions=False, ) assert result.exit_code == 0, result.output assert captured_config["config"].anyllm_provider == "llamacpp" def test_anyllm_provider_cli_flag_works(self, runner): """--anyllm-provider flag should still work.""" captured_config = {} def mock_run_server(config, **kwargs): captured_config["config"] = config with patch("headroom.proxy.server.run_server", mock_run_server): result = runner.invoke( main, ["proxy", "--backend", "anyllm", "--anyllm-provider", "groq"], catch_exceptions=False, ) assert result.exit_code == 0, result.output assert captured_config["config"].anyllm_provider == "groq" class TestCLICompressionOnlyFlags: """The CCR opt-out flags must flip the corresponding ProxyConfig fields. These enable a compression-only deployment for streaming / non-MCP clients that can't resolve the injected headroom_retrieve tool (issue #645). """ def test_ccr_defaults_on(self, runner): """Without flags, all three CCR toggles stay enabled (no behavior change).""" captured_config = {} def mock_run_server(config, **kwargs): captured_config["config"] = config with patch("headroom.proxy.server.run_server", mock_run_server): result = runner.invoke(main, ["proxy"], catch_exceptions=False) assert result.exit_code == 0, result.output cfg = captured_config["config"] assert cfg.ccr_inject_tool is True assert cfg.ccr_inject_marker is True assert cfg.ccr_proactive_expansion is True def test_no_ccr_flag(self, runner): """--no-ccr disables BOTH the retrieve-tool injection and the markers.""" captured_config = {} def mock_run_server(config, **kwargs): captured_config["config"] = config with patch("headroom.proxy.server.run_server", mock_run_server): result = runner.invoke(main, ["proxy", "--no-ccr"], catch_exceptions=False) assert result.exit_code == 0, result.output cfg = captured_config["config"] assert cfg.ccr_inject_tool is False assert cfg.ccr_inject_marker is False # Unrelated CCR knob stays on. assert cfg.ccr_proactive_expansion is True def test_compression_only_all_flags(self, runner): """--no-ccr + --no-ccr-proactive-expansion yields a compression-only config.""" captured_config = {} def mock_run_server(config, **kwargs): captured_config["config"] = config with patch("headroom.proxy.server.run_server", mock_run_server): result = runner.invoke( main, [ "proxy", "--no-ccr", "--no-ccr-proactive-expansion", ], catch_exceptions=False, ) assert result.exit_code == 0, result.output cfg = captured_config["config"] assert cfg.ccr_inject_tool is False assert cfg.ccr_inject_marker is False assert cfg.ccr_proactive_expansion is False def test_no_ccr_from_env(self, runner): """HEADROOM_NO_CCR env var disables both markers and tool injection.""" captured_config = {} def mock_run_server(config, **kwargs): captured_config["config"] = config with patch("headroom.proxy.server.run_server", mock_run_server): result = runner.invoke( main, ["proxy"], env={"HEADROOM_NO_CCR": "1"}, catch_exceptions=False, ) assert result.exit_code == 0, result.output cfg = captured_config["config"] assert cfg.ccr_inject_marker is False assert cfg.ccr_inject_tool is False class TestNoCcrMarkerCompressors: """Verify --no-ccr actually suppresses <> markers from every compressor, not just SmartCrusher (#1022).""" def test_content_router_propagates_ccr_inject_marker_false_to_compressors(self): """#1022: ContentRouter must pass enable_ccr=False to compressors when ccr_inject_marker=False. Before the fix, only SmartCrusher received the flag — Search/Log/Diff compressors always got enable_ccr=True (the default).""" from headroom.transforms.content_router import ( ContentRouter, ContentRouterConfig, ) router = ContentRouter(ContentRouterConfig(ccr_inject_marker=False, ccr_enabled=True)) # search compressor sc = router._get_search_compressor() assert sc is not None assert sc.config.enable_ccr is False, ( f"SearchCompressor enable_ccr={sc.config.enable_ccr}, expected False" ) # log compressor lc = router._get_log_compressor() assert lc is not None assert lc.config.enable_ccr is False, ( f"LogCompressor enable_ccr={lc.config.enable_ccr}, expected False" ) # diff compressor dc = router._get_diff_compressor() assert dc is not None assert dc.config.enable_ccr is False, ( f"DiffCompressor enable_ccr={dc.config.enable_ccr}, expected False" ) # SmartCrusher already works (regression guard) sc2 = router._get_smart_crusher() assert sc2 is not None # SmartCrusher uses inject_retrieval_marker, not enable_ccr def test_content_router_default_ccr_inject_marker_true(self): """Default config (ccr_inject_marker=True) should give enable_ccr=True.""" from headroom.transforms.content_router import ( ContentRouter, ContentRouterConfig, ) router = ContentRouter(ContentRouterConfig()) sc = router._get_search_compressor() assert sc.config.enable_ccr is True lc = router._get_log_compressor() assert lc.config.enable_ccr is True dc = router._get_diff_compressor() assert dc.config.enable_ccr is True def test_search_compressor_suppresses_markers_with_enable_ccr_false(self): """SearchCompressor with enable_ccr=False must not emit < int:\n" ' """Docstring for func_{i}."""\n' " # Line {j}\n" " result = x + {j}\n" " result *= 2\n" " return result\n" ) content = "\n".join(func_template.format(i=i, j=j) for i in range(30) for j in range(1, 6)) compressor = CodeAwareCompressor( CodeCompressorConfig(enable_ccr=False, min_tokens_for_compression=1) ) result = compressor.compress(content) assert "<