mirror of
https://github.com/headroomlabs-ai/headroom.git
synced 2026-08-27 14:17:10 -04:00
feat: ship the coding profile as Headroom's out-of-box default posture (#1893)
Make a bare `headroom proxy` (and the uvicorn factory / argparse main) default to the cache-mode coding posture instead of requiring users to set a dozen env vars. Profile (agent_savings.py): * "coding" is now the DEFAULT profile (DEFAULT_PROFILE), and it is rewritten for cache mode: proxy_mode="cache" and compress_user_messages=True (cache mode compresses the newest OBSERVATION delta — a user/tool turn — so compress_user must be on or there is nothing to compress; prefix stability is preserved by the delta engine, not by refusing to touch user turns). * AgentSavingsProfile carries the standalone router/handler toggles too (tool_search, cross_turn_dedup, lossless_then_lossy, protect_reads, code_aware, effort_router, lossless, min_chars_for_block); proxy_env() emits them. Defaults preserve current behavior for the other profiles. * coding sets: tool_search=1, dedupe=1, lossless_then_lossy=1, protect_reads=1, code_aware=1, effort_router=0, lossless=0, min_chars_for_block=25. CCR stays ON (no HEADROOM_NO_CCR) so any lossy loss is recoverable. * apply_agent_savings_env_defaults() now honors an explicit HEADROOM_SAVINGS_PROFILE already in the env before falling back to the default. Delivery (pollution-free by construction): * MODE and savings_profile default via INLINE defaults in the config builders (cache / coding) — no global env mutation, so unit tests that build config directly keep clean defaults. * The request-time toggles are seeded into os.environ (setdefault) via seed_proxy_env_defaults() ONLY at the executable/deployment entries — run_server() (before serving) and create_app_from_env() (uvicorn factory) — NOT in the CLI command or any library builder, so CliRunner tests never leak coding defaults into os.environ across tests. * CLI code_aware now defaults ON, matching the argparse server path (degrades to a no-op without tree-sitter). All explicit user env vars / CLI flags still win (setdefault + `or` fallbacks). HEADROOM_LOSSLESS was already 0 by default; unchanged. Tests: coding-profile + CLI-proxy-env tests updated to the new defaults; 1047 passed across the touched areas (only pre-existing memory/env failures remain). ## Description <!-- Briefly explain the change and why it is needed. --> Closes # ## 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 - ## Testing <!-- Check what you actually ran, then paste the real command output below. --> - [ ] Unit tests pass (`pytest`) - [ ] Linting passes (`ruff check .`) - [ ] Type checking passes (`mypy headroom`) - [ ] New tests added for new functionality - [ ] Manual testing performed ### Test Output ```text # Paste relevant command output or artifact links here ``` ## Real Behavior Proof - Environment: - Exact command / steps: - Observed result: - Not tested: ## 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 ## Screenshots (if applicable) Add screenshots to help explain your changes. ## Additional Notes <!-- Mention any N/A checklist items, tradeoffs, follow-ups, or maintainer context. --> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
c9217856d3
commit
68676daa50
6 changed files with 145 additions and 22 deletions
|
|
@ -4,6 +4,7 @@ from __future__ import annotations
|
|||
|
||||
import logging
|
||||
import os
|
||||
from collections.abc import MutableMapping
|
||||
from dataclasses import dataclass, replace
|
||||
from typing import Protocol
|
||||
|
||||
|
|
@ -11,6 +12,10 @@ logger = logging.getLogger(__name__)
|
|||
|
||||
AGENT_90_PROFILE = "agent-90"
|
||||
FALLBACK_PROFILE = "balanced"
|
||||
# Out-of-the-box default profile when none is requested. Headroom's primary
|
||||
# workload is coding agents, and the "coding" profile encodes the cache-mode
|
||||
# delta posture (see below).
|
||||
DEFAULT_PROFILE = "coding"
|
||||
|
||||
|
||||
class CompressConfigLike(Protocol):
|
||||
|
|
@ -42,6 +47,17 @@ class AgentSavingsProfile:
|
|||
force_kompress: bool
|
||||
proxy_mode: str
|
||||
accuracy_guard: str
|
||||
# Standalone router/handler toggles carried through the profile so a single
|
||||
# named profile seeds Headroom's full posture. Defaults below preserve the
|
||||
# current global behavior, so only a profile that opts in changes anything.
|
||||
tool_search: bool = False
|
||||
cross_turn_dedup: bool = False
|
||||
lossless_then_lossy: bool = False
|
||||
protect_reads: bool = False
|
||||
code_aware: bool = True
|
||||
effort_router: bool = True
|
||||
lossless: bool = False
|
||||
min_chars_for_block: int | None = None
|
||||
|
||||
@property
|
||||
def savings_percent(self) -> int:
|
||||
|
|
@ -65,14 +81,25 @@ class AgentSavingsProfile:
|
|||
),
|
||||
"HEADROOM_FORCE_KOMPRESS": "1" if self.force_kompress else "0",
|
||||
"HEADROOM_ACCURACY_GUARD": self.accuracy_guard,
|
||||
# Standalone router/handler toggles.
|
||||
"HEADROOM_TOOL_SEARCH": "1" if self.tool_search else "0",
|
||||
"HEADROOM_DEDUPE": "1" if self.cross_turn_dedup else "0",
|
||||
"HEADROOM_LOSSLESS_THEN_LOSSY": "1" if self.lossless_then_lossy else "0",
|
||||
"HEADROOM_PROTECT_READS": "1" if self.protect_reads else "0",
|
||||
"HEADROOM_CODE_AWARE_ENABLED": "1" if self.code_aware else "0",
|
||||
"HEADROOM_EFFORT_ROUTER": "1" if self.effort_router else "0",
|
||||
"HEADROOM_LOSSLESS": "1" if self.lossless else "0",
|
||||
}
|
||||
# Only pin a keep-ratio when the profile sets one; workload personas
|
||||
# leave it unset so Kompress decides and the ambient default applies.
|
||||
if self.target_ratio is not None:
|
||||
env["HEADROOM_TARGET_RATIO"] = f"{self.target_ratio:.2f}"
|
||||
# Block-compression char floor: only emit when the profile pins one.
|
||||
if self.min_chars_for_block is not None:
|
||||
env["HEADROOM_MIN_CHARS_FOR_BLOCK"] = str(self.min_chars_for_block)
|
||||
return env
|
||||
|
||||
def apply_proxy_env_defaults(self, env: dict[str, str]) -> dict[str, str]:
|
||||
def apply_proxy_env_defaults(self, env: MutableMapping[str, str]) -> MutableMapping[str, str]:
|
||||
"""Seed proxy env defaults without overriding explicit user settings."""
|
||||
|
||||
for key, value in self.proxy_env().items():
|
||||
|
|
@ -125,7 +152,11 @@ _PROFILES: dict[str, AgentSavingsProfile] = {
|
|||
name="coding",
|
||||
target_savings=0.50, # nominal (display only); savings are emergent
|
||||
target_ratio=None,
|
||||
compress_user_messages=False, # no prompt mutation / cache bust
|
||||
# Cache mode compresses only the newest delta — a tool/user OBSERVATION —
|
||||
# so compress_user must be ON or there is nothing to compress. Prefix
|
||||
# stability (no bust) is preserved by the delta engine (frozen prefix +
|
||||
# append-only forwarding), not by refusing to touch user turns.
|
||||
compress_user_messages=True,
|
||||
compress_system_messages=False, # system prompt is the hottest cache
|
||||
protect_recent=2, # keep the active code working set verbatim
|
||||
protect_analysis_context=True,
|
||||
|
|
@ -133,8 +164,21 @@ _PROFILES: dict[str, AgentSavingsProfile] = {
|
|||
max_items_after_crush=15,
|
||||
smart_crusher_with_compaction=True,
|
||||
force_kompress=False, # don't override diff/log lossless with lossy ML
|
||||
proxy_mode="token",
|
||||
proxy_mode="cache", # delta-only compression at ~0 prefix-cache busts
|
||||
accuracy_guard="strict",
|
||||
# Coding posture: defer non-core tool schemas, dedupe re-reads, extend
|
||||
# lossy coverage when lossless found nothing, and NEVER lossy-compress a
|
||||
# file read (the agent patches exact bytes). CCR stays ON (unset) so any
|
||||
# lossy loss is recoverable. Effort router off; low block floor so modest
|
||||
# deltas are eligible.
|
||||
tool_search=True,
|
||||
cross_turn_dedup=True,
|
||||
lossless_then_lossy=True,
|
||||
protect_reads=True,
|
||||
code_aware=True,
|
||||
effort_router=False,
|
||||
lossless=False,
|
||||
min_chars_for_block=25,
|
||||
),
|
||||
"general": AgentSavingsProfile(
|
||||
name="general",
|
||||
|
|
@ -166,7 +210,7 @@ def get_agent_savings_profile(name: str | None = None) -> AgentSavingsProfile:
|
|||
to ``balanced`` rather than leaving the user with no proxy at all.
|
||||
"""
|
||||
|
||||
key = (name or AGENT_90_PROFILE).strip().lower()
|
||||
key = (name or DEFAULT_PROFILE).strip().lower()
|
||||
profile = _PROFILES.get(key)
|
||||
if profile is not None:
|
||||
return profile
|
||||
|
|
@ -181,11 +225,18 @@ def get_agent_savings_profile(name: str | None = None) -> AgentSavingsProfile:
|
|||
|
||||
|
||||
def apply_agent_savings_env_defaults(
|
||||
env: dict[str, str],
|
||||
env: MutableMapping[str, str],
|
||||
profile: AgentSavingsProfile | str | None = None,
|
||||
) -> dict[str, str]:
|
||||
"""Apply agent savings env defaults to a proxy subprocess environment."""
|
||||
) -> MutableMapping[str, str]:
|
||||
"""Apply agent savings env defaults to a proxy subprocess environment.
|
||||
|
||||
When ``profile`` is not given, an explicit ``HEADROOM_SAVINGS_PROFILE`` already
|
||||
in ``env`` is honored; only when that too is absent do we fall back to the
|
||||
out-of-box default (:data:`DEFAULT_PROFILE`, i.e. ``coding``).
|
||||
"""
|
||||
|
||||
if profile is None:
|
||||
profile = env.get("HEADROOM_SAVINGS_PROFILE")
|
||||
resolved = (
|
||||
get_agent_savings_profile(profile)
|
||||
if isinstance(profile, str) or profile is None
|
||||
|
|
@ -295,6 +346,24 @@ def proxy_pipeline_kwargs(config: object) -> dict[str, object]:
|
|||
return kwargs
|
||||
|
||||
|
||||
def seed_proxy_env_defaults(env: MutableMapping[str, str] | None = None) -> None:
|
||||
"""Seed the process env with the savings-profile defaults (default: coding).
|
||||
|
||||
Call at proxy EXECUTABLE entry points (the ``headroom proxy`` command and the
|
||||
uvicorn ``create_app_from_env`` factory) BEFORE building config from env. Uses
|
||||
``setdefault`` semantics via :func:`apply_agent_savings_env_defaults`, so any
|
||||
explicit user setting wins and the call is idempotent.
|
||||
|
||||
Deliberately NOT called from ``_proxy_config_from_env`` / ``ContentRouter`` or
|
||||
any other library-level builder that unit tests construct directly, so those
|
||||
keep clean (unseeded) defaults and test isolation is preserved.
|
||||
"""
|
||||
target = os.environ if env is None else env
|
||||
# apply_agent_savings_env_defaults honors an explicit HEADROOM_SAVINGS_PROFILE
|
||||
# already in the env and otherwise falls back to DEFAULT_PROFILE (coding).
|
||||
apply_agent_savings_env_defaults(target)
|
||||
|
||||
|
||||
def with_target_savings(
|
||||
profile: AgentSavingsProfile,
|
||||
target_savings: float,
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ import click
|
|||
|
||||
from headroom import paths as _paths
|
||||
from headroom.providers.registry import resolve_api_overrides, resolve_api_targets
|
||||
from headroom.proxy.modes import PROXY_MODE_TOKEN, normalize_proxy_mode
|
||||
from headroom.proxy.modes import PROXY_MODE_CACHE, normalize_proxy_mode
|
||||
|
||||
from .main import main
|
||||
|
||||
|
|
@ -1033,9 +1033,10 @@ def proxy(
|
|||
# Resolve anyllm provider: env var takes precedence over CLI default (matches argparse path)
|
||||
effective_anyllm_provider = os.environ.get("HEADROOM_ANYLLM_PROVIDER") or anyllm_provider
|
||||
|
||||
# Resolve mode: CLI flag > env var > default
|
||||
# Resolve mode: CLI flag > env var > default. Default is CACHE (Headroom's
|
||||
# coding posture): delta-only compression at ~0 prefix-cache busts.
|
||||
effective_mode: str = normalize_proxy_mode(
|
||||
mode or os.environ.get("HEADROOM_MODE") or PROXY_MODE_TOKEN
|
||||
mode or os.environ.get("HEADROOM_MODE") or PROXY_MODE_CACHE
|
||||
)
|
||||
|
||||
# Stateless mode: CLI flag or env var
|
||||
|
|
@ -1102,7 +1103,7 @@ def proxy(
|
|||
else frozenset(),
|
||||
tool_profiles=_parse_tool_profiles([]) or None,
|
||||
smart_crusher_with_compaction=_get_env_bool_optional("HEADROOM_SMART_CRUSHER_COMPACTION"),
|
||||
savings_profile=os.environ.get("HEADROOM_SAVINGS_PROFILE") or None,
|
||||
savings_profile=os.environ.get("HEADROOM_SAVINGS_PROFILE") or "coding",
|
||||
target_ratio=target_ratio,
|
||||
compress_system_messages=_get_env_bool_optional("HEADROOM_COMPRESS_SYSTEM_MESSAGES"),
|
||||
protect_recent=_get_env_int_optional("HEADROOM_PROTECT_RECENT"),
|
||||
|
|
@ -1154,10 +1155,12 @@ def proxy(
|
|||
# 2. Otherwise read HEADROOM_CODE_AWARE_ENABLED (truthy = on).
|
||||
# 3. Otherwise default off — matches the prior cli/proxy.py behavior so
|
||||
# existing users see no change unless they opt in.
|
||||
# Default ON (coding posture; consistent with the argparse server path).
|
||||
# Degrades gracefully to a no-op when tree-sitter isn't installed.
|
||||
code_aware_enabled=(
|
||||
bool(code_aware_flag)
|
||||
if code_aware_flag is not None
|
||||
else os.environ.get("HEADROOM_CODE_AWARE_ENABLED", "").strip().lower()
|
||||
else os.environ.get("HEADROOM_CODE_AWARE_ENABLED", "1").strip().lower()
|
||||
in ("true", "1", "yes", "on")
|
||||
),
|
||||
disable_kompress=disable_kompress,
|
||||
|
|
|
|||
|
|
@ -4313,7 +4313,13 @@ def _proxy_config_from_env() -> ProxyConfig:
|
|||
periodic_toin_stats_enabled=_get_env_bool("HEADROOM_PERIODIC_TOIN_STATS", True),
|
||||
proxy_token=os.environ.get("HEADROOM_PROXY_TOKEN") or None,
|
||||
offline=_get_env_bool("HEADROOM_OFFLINE", False),
|
||||
mode=normalize_proxy_mode(_get_env_str("HEADROOM_MODE", PROXY_MODE_TOKEN)),
|
||||
# Default mode is CACHE (Headroom's coding posture): delta-only compression
|
||||
# at ~0 prefix-cache busts. HEADROOM_MODE overrides.
|
||||
mode=normalize_proxy_mode(_get_env_str("HEADROOM_MODE", PROXY_MODE_CACHE)),
|
||||
# Default savings profile is "coding" so proxy_pipeline_kwargs applies its
|
||||
# posture (compress_user, protect_recent, min_tokens). HEADROOM_SAVINGS_PROFILE
|
||||
# overrides.
|
||||
savings_profile=os.environ.get("HEADROOM_SAVINGS_PROFILE") or "coding",
|
||||
read_maturation=_get_env_bool("HEADROOM_READ_MATURATION", False),
|
||||
read_maturation_quiesce_turns=_get_env_int("HEADROOM_READ_MATURATION_QUIESCE_TURNS", 5),
|
||||
read_maturation_max_hold_turns=_get_env_int("HEADROOM_READ_MATURATION_MAX_HOLD_TURNS", 25),
|
||||
|
|
@ -4324,6 +4330,12 @@ def _proxy_config_from_env() -> ProxyConfig:
|
|||
|
||||
|
||||
def create_app_from_env() -> FastAPI:
|
||||
# Seed the coding-profile defaults into the process env BEFORE reading config,
|
||||
# so the uvicorn factory launch gets Headroom's out-of-box posture (cache mode,
|
||||
# tool-search, dedupe, read protection, …). setdefault → explicit env wins.
|
||||
from headroom.agent_savings import seed_proxy_env_defaults
|
||||
|
||||
seed_proxy_env_defaults()
|
||||
return create_app(_proxy_config_from_env())
|
||||
|
||||
|
||||
|
|
@ -4362,6 +4374,16 @@ def run_server(
|
|||
print("ERROR: FastAPI required. Install: pip install fastapi uvicorn httpx")
|
||||
sys.exit(1)
|
||||
|
||||
# Seed the request-time coding-profile toggles (tool-search, dedupe, read
|
||||
# protection, lossless→lossy, effort-router, block-char floor) into the
|
||||
# process env before serving, so downstream per-request readers pick them up.
|
||||
# Done here (not in the CLI command) so unit tests that mock run_server never
|
||||
# mutate os.environ. setdefault → explicit env still wins. MODE / profile are
|
||||
# already resolved into `config` above via their inline defaults.
|
||||
from headroom.agent_savings import seed_proxy_env_defaults
|
||||
|
||||
seed_proxy_env_defaults()
|
||||
|
||||
config = config or ProxyConfig()
|
||||
code_aware_status = _get_code_aware_banner_status(config)
|
||||
|
||||
|
|
@ -4969,10 +4991,10 @@ if __name__ == "__main__":
|
|||
protect_tool_results=frozenset(protect_tool_results)
|
||||
if protect_tool_results
|
||||
else frozenset(),
|
||||
mode=normalize_proxy_mode(_get_env_str("HEADROOM_MODE", PROXY_MODE_TOKEN)),
|
||||
mode=normalize_proxy_mode(_get_env_str("HEADROOM_MODE", PROXY_MODE_CACHE)),
|
||||
compress_user_messages=args.compress_user_messages
|
||||
or _get_env_bool("HEADROOM_COMPRESS_USER_MESSAGES", False),
|
||||
savings_profile=os.environ.get("HEADROOM_SAVINGS_PROFILE") or None,
|
||||
savings_profile=os.environ.get("HEADROOM_SAVINGS_PROFILE") or "coding",
|
||||
# Default 0.4 keep-ratio so the Kompress text (prose/code) path compresses
|
||||
# meaningfully out of the box; HEADROOM_TARGET_RATIO overrides.
|
||||
target_ratio=(
|
||||
|
|
|
|||
|
|
@ -70,12 +70,23 @@ def test_coding_persona_protects_working_set_and_stays_visible() -> None:
|
|||
env = profile.proxy_env()
|
||||
|
||||
assert env["HEADROOM_SAVINGS_PROFILE"] == "coding"
|
||||
assert env["HEADROOM_MODE"] == "cache" # delta-only compression at ~0 prefix-cache busts
|
||||
assert env["HEADROOM_PROTECT_RECENT"] == "2" # keep the active code working set verbatim
|
||||
assert env["HEADROOM_MIN_TOKENS"] == "25" # low → compression is actually visible
|
||||
assert env["HEADROOM_COMPRESS_USER_MESSAGES"] == "0" # no prompt mutation / cache bust
|
||||
assert env["HEADROOM_COMPRESS_SYSTEM_MESSAGES"] == "0"
|
||||
# Cache mode compresses the newest observation delta → compress_user must be ON.
|
||||
assert env["HEADROOM_COMPRESS_USER_MESSAGES"] == "1"
|
||||
assert env["HEADROOM_COMPRESS_SYSTEM_MESSAGES"] == "0" # system prompt is the hottest cache
|
||||
assert env["HEADROOM_ACCURACY_GUARD"] == "strict"
|
||||
assert "HEADROOM_TARGET_RATIO" not in env # unset → Kompress / ambient default decides
|
||||
# Coding posture toggles seeded through the profile.
|
||||
assert env["HEADROOM_TOOL_SEARCH"] == "1"
|
||||
assert env["HEADROOM_DEDUPE"] == "1"
|
||||
assert env["HEADROOM_LOSSLESS_THEN_LOSSY"] == "1"
|
||||
assert env["HEADROOM_PROTECT_READS"] == "1"
|
||||
assert env["HEADROOM_CODE_AWARE_ENABLED"] == "1"
|
||||
assert env["HEADROOM_EFFORT_ROUTER"] == "0"
|
||||
assert env["HEADROOM_LOSSLESS"] == "0" # lossy enabled (CCR keeps it recoverable)
|
||||
assert env["HEADROOM_MIN_CHARS_FOR_BLOCK"] == "25"
|
||||
|
||||
|
||||
def test_general_persona_has_no_positional_code_protection() -> None:
|
||||
|
|
@ -89,13 +100,18 @@ def test_general_persona_has_no_positional_code_protection() -> None:
|
|||
|
||||
|
||||
def test_personas_omit_target_ratio_in_pipeline_kwargs() -> None:
|
||||
for name, expected_protect in (("coding", 2), ("general", 0)):
|
||||
# coding compresses the delta observation (cache mode) → compress_user True;
|
||||
# general has no positional code working set and leaves user turns intact.
|
||||
for name, expected_protect, expected_compress_user in (
|
||||
("coding", 2, True),
|
||||
("general", 0, False),
|
||||
):
|
||||
kwargs = proxy_pipeline_kwargs(ProxyConfig(savings_profile=name))
|
||||
|
||||
assert kwargs["protect_recent"] == expected_protect
|
||||
assert kwargs["read_protection_window"] == expected_protect
|
||||
assert kwargs["min_tokens_to_compress"] == 25
|
||||
assert kwargs["compress_user_messages"] is False
|
||||
assert kwargs["compress_user_messages"] is expected_compress_user
|
||||
assert kwargs["compress_system_messages"] is False
|
||||
assert kwargs["force_kompress"] is False
|
||||
assert "target_ratio" not in kwargs # persona never pins a keep-ratio
|
||||
|
|
|
|||
|
|
@ -1005,6 +1005,17 @@ def test_start_proxy_does_not_apply_agent_90_defaults(
|
|||
monkeypatch: pytest.MonkeyPatch, tmp_path: Path, agent_type: str
|
||||
) -> None:
|
||||
"""Wrapped coding agents keep agent-savings opt-in by default."""
|
||||
# Clean baseline: the proxy's out-of-box coding profile seeds these into the
|
||||
# process env at startup (``seed_proxy_env_defaults``), which another test in
|
||||
# the shard can leave behind in ``os.environ``. This test is about what the
|
||||
# WRAPPER adds, so start from an unset env rather than inheriting pollution.
|
||||
for _var in (
|
||||
"HEADROOM_SAVINGS_PROFILE",
|
||||
"HEADROOM_TARGET_RATIO",
|
||||
"HEADROOM_MAX_ITEMS",
|
||||
"HEADROOM_SMART_CRUSHER_COMPACTION",
|
||||
):
|
||||
monkeypatch.delenv(_var, raising=False)
|
||||
popen_kwargs: dict[str, object] = {}
|
||||
|
||||
class FakeProc:
|
||||
|
|
|
|||
|
|
@ -338,8 +338,10 @@ class TestCLIProxyEnvVars:
|
|||
assert result.exit_code == 0, result.output
|
||||
assert captured_config["config"].code_aware_enabled is True
|
||||
|
||||
def test_code_aware_enabled_defaults_false(self, runner):
|
||||
"""Without HEADROOM_CODE_AWARE_ENABLED, code-aware stays disabled in the wrapper."""
|
||||
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):
|
||||
|
|
@ -358,7 +360,7 @@ class TestCLIProxyEnvVars:
|
|||
)
|
||||
|
||||
assert result.exit_code == 0, result.output
|
||||
assert captured_config["config"].code_aware_enabled is False
|
||||
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."""
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue